const {
	Service
} = require('uni-cloud-router')
const uniID = require('uni-id')
const dbHelper = require('db-helper')
const dbUtil = require('db-util')
const orderHelper = require('order-helper')
const payUtil = require("pay-util")
const moment = require('moment-timezone')
const tokenUtil = require("token-util")
const md5 = require("md5-node")
const {
	CLOUDURL
} = require('config')
const {
	wxPubConfig
} = require("config");
const WxPubApi = require("wx-public-api")
const wxPubApi = new WxPubApi(wxPubConfig.appId, wxPubConfig.appSecret)
const oneHourInMills = 60 * 60 * 1000

function format(d) {
	let t = `${d}`;
	if (t.length < 2) {
		return `0${t}`;
	}
	return t;
}

function newDate(year, month, day, hours, minutes, seconds) {
	let dateStr =
		`${year}-${format(month + 1)}-${format(day)} ${format(hours)}:${format(minutes)}:${format(seconds)} GMT+0800`
	// console.log("dateStr", dateStr)
	let d = new Date(dateStr);
	// d.setFullYear(year);
	// d.setMonth(month);
	// d.setDate(day);
	// d.setHours(hours);
	// d.setMinutes(minutes);
	// d.setSeconds(seconds);
	return d;
}

function getTodayRange() {
	let now = new Date();
	let startDate = newDate(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);
	let endDate = newDate(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59);
	return {
		startTime: startDate.getTime(),
		endTime: endDate.getTime()
	}
}

function getThisWeekRange() {
	let now = new Date();
	let weekDay = now.getDay();
	var startDate = new Date();
	var endDate = new Date();

	switch (weekDay) {
		case 0:
			startDate.setDate(startDate.getDate() - 6);
			break;
		case 1:
			endDate.setDate(endDate.getDate() + 6);
			break;
		case 2:
			startDate.setDate(startDate.getDate() - 1);
			endDate.setDate(endDate.getDate() + 5);
			break;
		case 3:
			startDate.setDate(startDate.getDate() - 2);
			endDate.setDate(endDate.getDate() + 4);
			break;
		case 4:
			startDate.setDate(startDate.getDate() - 3);
			endDate.setDate(endDate.getDate() + 3);
			break;
		case 5:
			startDate.setDate(startDate.getDate() - 4);
			endDate.setDate(endDate.getDate() + 2);
			break;
		case 6:
			startDate.setDate(startDate.getDate() - 5);
			endDate.setDate(endDate.getDate() + 1);
			break;
	}

	var y = startDate.getFullYear();
	var m = startDate.getMonth();
	var d = startDate.getDate();
	startDate = newDate(y, m, d, 0, 0, 0);
	y = endDate.getFullYear();
	m = endDate.getMonth();
	d = endDate.getDate();
	endDate = newDate(y, m, d, 23, 59, 59);
	return {
		startTime: startDate.getTime(),
		endTime: endDate.getTime()
	}
}

function getThisMonthRange() {
	let now = new Date();
	let day = now.getDate();
	var startDate = new Date();
	startDate.setDate(1)

	var date = new Date();
	var year = date.getFullYear();
	var month = date.getMonth() + 1;
	var days = new Date(year, month, 0).getDate();
	var endDate = new Date();
	endDate.setDate(days);

	var y = startDate.getFullYear();
	var m = startDate.getMonth();
	var d = startDate.getDate();
	startDate = newDate(y, m, d, 0, 0, 0);

	y = endDate.getFullYear();
	m = endDate.getMonth();
	d = endDate.getDate();
	endDate = newDate(y, m, d, 23, 59, 59);
	return {
		startTime: startDate.getTime(),
		endTime: endDate.getTime()
	}
}

function getThisYearRange() {
	var startDate = new Date();
	startDate.setMonth(0);
	startDate.setDate(1);

	var endDate = new Date();
	endDate.setMonth(11);
	var days = new Date(endDate.getFullYear(), 12, 0).getDate();
	endDate.setDate(days);

	var y = startDate.getFullYear();
	var m = startDate.getMonth();
	var d = startDate.getDate();
	startDate = newDate(y, m, d, 0, 0, 0);

	y = endDate.getFullYear();
	m = endDate.getMonth();
	d = endDate.getDate();
	endDate = newDate(y, m, d, 23, 59, 59);
	return {
		startTime: startDate.getTime(),
		endTime: endDate.getTime()
	}
}

function getData() {
	return {
		orderCount: 0, //订单数
		sales: 0, //销售额
		brokerage: 0, //佣金
		settlement: 0, //商家结算金额
		profit: 0, //利润
	}
}

// 获取预约订单列表数据-getSubscribeOrderList
async function getSubscribeOrderData(type, query, pageNum, pageSize) {
	const db = uniCloud.database()
	const dbCmd = db.command
	const $ = dbCmd.aggregate

	// 由后台通过取消订单结算的剧本杀订单，其结束时间已过则在前台不显示
	// let noQuery = dbCmd.expr(
	//   dbCmd.or(
	//     dbCmd.neq(['$status', 3]),
	//     dbCmd.and(
	//       dbCmd.eq(['$status', 3]),
	//       dbCmd.gt(['$motorcade.endTime', Date.now()])
	//     )
	//   )
	// )

	switch (type) {
		case 'total':
			let {
				data: countRes
			} = await db.collection("t3ds-order")
				.aggregate()
				.match(query)
				.lookup({
					from: "t3ds-subscribe-motorcade",
					localField: "motorcadeId",
					foreignField: "_id",
					as: "motorcade"
				})
				.unwind({
					path: '$motorcade',
					preserveNullAndEmptyArrays: true
				})
				// .match(noQuery)
				.count('total')
				.end()
			if (Array.isArray(countRes) && countRes.length) return countRes[0].total || 0
			return countRes || 0
		case 'list':
			let res = await db.collection("t3ds-order")
				.aggregate()
				.match(query)
				.lookup({
					from: "t3ds-subscribe-motorcade",
					let: {
						motorcadeId: '$motorcadeId'
					},
					pipeline: $.pipeline()
						.match(dbCmd.expr($.eq(['$_id', '$$motorcadeId'])))
						.project({
							name: 1,
							storeName: 1,
							roomId: 1,
							roomName: 1,
							orderIds: 1,
							startTime: 1,
							endTime: 1,
							initiator: 1,
							costPerPerson: 1,
							maxPlayers: 1,
							minPlayers: 1,
							currentMaleCount: 1,
							currentFemaleCount: 1,
							status: 1,
							renewalOrders: 1
						})
						.done(),
					as: 'motorcade'
				})
				.unwind({
					path: '$motorcade',
					preserveNullAndEmptyArrays: true
				})
				// .match(noQuery)
				.sort({
					'create_time': -1,
					'pay_time': -1,
				})
				.skip((pageNum - 1) * pageSize)
				.limit(pageSize)
				.addFields({
					items0: $.arrayElemAt(['$items', 0])
				})
				.lookup({
					from: 't3ds-store',
					let: {
						storeId: '$items0.store_id'
					},
					pipeline: $.pipeline()
						.match(dbCmd.expr($.eq(['$_id', '$$storeId'])))
						.project({
							storeName: 1,
							location: 1,
							address: 1,
							phone: 1,
							cooperationMode: 1
						})
						.done(),
					as: 'store',
				})
				.lookup({
					from: 't3ds-store-room',
					let: {
						roomId: '$items0.room_id'
					},
					pipeline: $.pipeline()
						.match(dbCmd.expr($.eq(['$_id', '$$roomId'])))
						.project({
							name: 1,
							photos: 1
						})
						.done(),
					as: 'room',
				})
				.lookup({
					from: 't3ds-script',
					let: {
						scriptId: '$items0.script_id'
					},
					pipeline: $.pipeline()
						.match(dbCmd.expr($.eq(['$_id', '$$scriptId'])))
						.project({
							name: 1,
							cover: 1,
							name: 1,
							cover: 1,
							playTime: 1,
							difficulty: 1,
							standardPlayers: 1,
							simpleTag: 1
						})
						.done(),
					as: 'script',
				})
				.unwind({
					path: '$store',
					preserveNullAndEmptyArrays: true
				})
				.unwind({
					path: '$room',
					preserveNullAndEmptyArrays: true
				})
				.unwind({
					path: '$script',
					preserveNullAndEmptyArrays: true
				})
				.end()
			return res;
		default:
			break;
	}
}

/* 校验优惠券 */
async function verifyCoupon(transaction, uid, couponId, startTime, orderType, storeId, motorcadeId) {
	try {
		let couponRes = null
		if (couponId) {
			couponRes = await dbHelper.getById("t3ds-coupon-member", couponId, transaction)
			console.log("couponRes: ", couponRes);
			if (!couponRes) {
				throw "此优惠券不存在"
			}
			if (couponRes.uid != uid) {
				throw "此优惠券不属于你"
			}
			if (couponRes.deadline <= Date.now()) {
				throw "此优惠券已过期"
			}
			if (couponRes.goodsType === 'script' && orderType !== 'subscribe') {
				if (orderType !== 'renewal' || !motorcadeId) {
					console.log(couponRes.goodsType, orderType, motorcadeId);
					throw "此优惠券仅供剧本使用"
				}
			}
			if (couponRes.initiator && (orderType === 'renewal' || motorcadeId)) {
				throw "此优惠券仅发起车队时使用"
			}
			if (couponRes.goodsType === 'tearoom' && orderType !== 'tearoom') {
				if (orderType !== 'renewal') {
					console.log(couponRes.goodsType, orderType, motorcadeId);
					throw "此优惠券仅供茶室使用"
				}
			}

			let weekday = moment.tz(Number(startTime), "Asia/Shanghai").day()
			if (couponRes.validDays.length && !couponRes.validDays.includes(weekday)) {
				let foo = []
				for (let item of couponRes.validDays) {
					switch (item) {
						case 1:
							foo.push('星期一')
							break;
						case 2:
							foo.push('星期二')
							break;
						case 3:
							foo.push('星期三')
							break;
						case 4:
							foo.push('星期四')
							break;
						case 5:
							foo.push('星期五')
							break;
						case 6:
							foo.push('星期六')
							break;
						case 0:
							foo.push('星期日')
							break;
						default:
							break;
					}
				}
				throw `此优惠券只能在 ${ foo.toString() } 使用`
			}

			if (couponRes.stores && couponRes.stores.length) {
				let storesName = []
				for (let i = 0; i < couponRes.stores.length; i++) {
					let res = await dbHelper.getById("t3ds-store", couponRes.stores[i], transaction)
					storesName.push(res.name)
				}
				couponRes.storesName = storesName
				if (!couponRes.stores.includes(storeId)) {
					throw `此优惠券仅在 ${ couponRes.storesName.toString() } 使用`
				}
			}
		}
		return couponRes
	} catch (e) {
		throw e
	}
}

/* 更新账户余额 */
async function updataAccountBalance(transaction, ctx, time, pricePerHour, room, store, count, coupon, useBalance) {
	let member = await dbHelper.getById("uni-id-users", ctx.auth.uid)
	let account = await dbHelper.getOne("t3ds-account", {
		userId: member._id
	});
	account = await dbHelper.getById("t3ds-account", account._id, transaction)
	let totalFee = 0
	if (pricePerHour) {
		totalFee = Math.round((pricePerHour || 0) + (room.price || store.unifyPrice || 0)) * time * count
		console.log(pricePerHour, room.price, store.unifyPrice, time, count);
	} else {
		totalFee = Math.round(room.price || store.unifyPrice || 0) * time
	}
	var paymentFee = totalFee,
		income, use_balance_fee, discountsForVip = 0,
		discount_fee = 0
	if (coupon) {
		if (totalFee < coupon.minOrderAmount) {
			throw `订单金额小于${ coupon.minOrderAmount / 100 }元无法使用此优惠券`
		}

		let t = coupon.value
		switch (coupon.type) {
			case 'percent': // 折扣券
				t = totalFee * (1 - t / 100)
				break;
			case 'deduction': // 抵扣劵
				t = totalFee < t ? totalFee : t
				break;
			case 'replace': // 面值券
				t = totalFee < t ? 0 : totalFee - t
				break;
			default:
				t = 0
				break;
		}
		discount_fee = Math.round(t) // 优惠的金额
		console.log("优惠金额: ", discount_fee);
		paymentFee = totalFee - discount_fee

		// 更新优惠券使用记录 - 更改为付款后更新优惠券
		// await transaction.collection('t3ds-coupon-member').doc(coupon._id).update({
		//   used: true,
		//   usedTime: Date.now(),
		//   updateTime: Date.now(),
		//   updateBy: ctx.auth.nickname || ctx.auth.username
		// });
	}
	if (discountsForVip) {
		paymentFee -= discountsForVip
	}
	if (paymentFee > 0 && useBalance && account.balance) {
		if (paymentFee > account.balance) {
			paymentFee = paymentFee - account.balance;
			use_balance_fee = account.balance
			account.frozen += account.balance;
			account.balance = 0;
			income = account.balance
		} else {
			use_balance_fee = paymentFee
			account.balance -= paymentFee;
			account.frozen += paymentFee;
			income = paymentFee;
			paymentFee = 0;
		}
		// 更新余额
		console.log("余额支付更新账户", account);
		await dbHelper.update("t3ds-account", account, transaction);
	}

	return {
		discountsForVip,
		totalFee,
		paymentFee,
		discount_fee,
		member,
		use_balance_fee,
		income,
		account
	}
}

module.exports = class OrderService extends Service {

	async getEvaluationPage({
		scriptId,
		goodsId,
		storeId,
		pageNum = 1,
		pageSize = 10,
		onlyOpen = true
	}) {
		let dbCmd = this.db.command
		let $ = dbCmd.aggregate
		let optArr = [
			$.eq(['$orderId', '$$orderId'])
		]
		if (onlyOpen) {
			optArr.push($.eq(['$open', true]))
		}
		var match = {},
			match2 = dbCmd.expr($.and(optArr))
		if (scriptId) {
			match = {
				'items.script_id': scriptId
			}
		} else if (goodsId) {
			match = {
				'items.goods_id': goodsId
			}
		} else if (storeId) {
			match = {
				'items.room_id': storeId
			}
		}
		let result = {
			total: 0,
			list: []
		}
		try {
			if (pageNum == 1) {
				let totalRes = await this.db.collection('t3ds-order')
					.aggregate()
					.match(match)
					.lookup({
						from: 't3ds-mall-goods-evaluation',
						let: {
							orderId: '$_id'
						},
						pipeline: $
							.pipeline()
							.match(match2)
							.done(),
						as: 'comment'
					})
					.unwind('$comment')
					.count('total')
					.end()
				if (totalRes.data.length) {
					result.total = totalRes.data[0].total
				}
			}
			if (!result.total) {
				return result
			}
			let res = await this.db.collection('t3ds-order')
				.aggregate()
				.match(match)
				.lookup({
					from: 't3ds-mall-goods-evaluation',
					let: {
						orderId: '$_id'
					},
					pipeline: $
						.pipeline()
						.match(match2)
						.done(),
					as: 'comment'
				})
				.unwind('$comment')
				.sort({
					'comment.orderNum': 1,
					'comment.createTime': -1
				})
				.skip((pageNum - 1) * pageSize)
				.limit(pageSize)
				.lookup({
					from: 'uni-id-users',
					let: {
						id: '$user_id'
					},
					pipeline: $
						.pipeline()
						.match(dbCmd.expr($.eq(['$_id', '$$id'])))
						.project({
							avatar: 1,
							nickname: 1
						})
						.done(),
					as: 'member'
				})
				.project({
					_id: "$comment._id",
					avatar: "$member.avatar",
					nickname: "$member.nickname",
					score: "$comment.score",
					description: "$comment.description",
					createTime: "$comment.createTime",
					open: "$comment.open",
					orderNum: "$comment.orderNum"
				})
				.project({
					_id: 1,
					avatar: $.arrayElemAt(['$avatar', 0]),
					nickname: $.arrayElemAt(['$nickname', 0]),
					score: 1,
					description: 1,
					createTime: 1,
					open: 1,
					orderNum: 1
				})
				.end()
			result.list = res.data
			return result
		} catch (e) {
			console.error(e)
			throw e
		}
	}

	async confirmSendTicket({
		orderId
	}) {
		let transaction = await this.db.startTransaction()
		try {
			let order = await dbHelper.getById("t3ds-order", orderId)
			if (!order) {
				throw new Error("订单不存在!")
			}
			if (order.status !== 2) {
				throw new Error("已确认出票，不能重复操作")
			}
			let user = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
			let action = {
				time: Date.now(),
				by: user.username,
				desc: '确认发码'
			}
			if (!order.modify_history) {
				await dbHelper.update("t3ds-order", {
					_id: orderId,
					status: 3,
					update_by: user.username,
					update_time: Date.now(),
					modify_history: [action]
				})
			} else {
				await dbHelper.update("t3ds-order", {
					_id: orderId,
					status: 3,
					update_by: user.username,
					update_time: Date.now(),
					['modify_history.' + order.modify_history.length]: action
				})
			}
			let orderItem = order.items[0]
			let goods = await dbHelper.getById("t3ds-mall-goods", orderItem.goods_id)
			if (goods.distribution) {
				let merchant = await dbHelper.getById("uni-id-users", goods.uid)
				let sku = await dbHelper.getById("t3ds-mall-sku", orderItem.sku_id, transaction)
				let buyMan = await dbHelper.getById("uni-id-users", order.user_id)
				var account = await dbHelper.getOne("t3ds-account", {
					userId: buyMan._id
				})
				account = await dbHelper.getById("t3ds-account", account._id, transaction)
				await orderHelper.handleDistribution(order, goods, merchant, sku, account, buyMan, transaction)
			}
			await transaction.commit()
		} catch (e) {
			console.error('确认发码遇到错误', e)
			await transaction.rollback()
		}
	}

	async confirmChargeoffed({
		orderId,
		usedCount = 0,
		overdueCount = 0
	}) {
		let transaction = await this.db.startTransaction()
		let dbCmd = this.db.command
		let $ = dbCmd.aggregate
		try {
			let order = await dbHelper.getById("t3ds-order", orderId)
			if (!order) {
				throw new Error("订单不存在!")
			}
			if (order.status !== 3) {
				throw new Error("已确认已核销的，不能重复操作")
			}
			let user = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
			let action = {
				time: Date.now(),
				by: user.username,
				desc: '确认已核销的'
			}
			let refundCountRes = await this.db.collection("t3ds-refund-apply").aggregate()
				.match({
					orderSn: orderId,
					status: dbCmd.neq('FAILED').and(dbCmd.neq('REJECTED'))
				})
				.group({
					_id: "$orderSn",
					count: $.sum("$count")
				})
				.end()
			var refundedCount = 0
			if (refundCountRes.data.length) {
				refundedCount = refundCountRes.data[0].count
			}
			if (usedCount + overdueCount + refundedCount > order.items[0].count) {
				throw new Error("数量不正确")
			}
			var status = 3
			if (usedCount + overdueCount + refundedCount === order.items[0].count) {
				status = 4
			}
			if (!order.modify_history) {
				await dbHelper.update("t3ds-order", {
					_id: orderId,
					status: status,
					usedCount,
					overdueCount,
					update_by: user.username,
					update_time: Date.now(),
					modify_history: [action]
				})
			} else {
				await dbHelper.update("t3ds-order", {
					_id: orderId,
					status: status,
					usedCount,
					overdueCount,
					update_by: user.username,
					update_time: Date.now(),
					['modify_history.' + order.modify_history.length]: action
				})
			}
			await transaction.commit()
		} catch (e) {
			console.error('确认发码遇到错误', e)
			await transaction.rollback()
			throw e
		}
	}

	async getRefundApplyDetail({
		applyId
	}) {
		try {
			let apply = await dbHelper.getById("t3ds-refund-apply", applyId)
			if (!apply) {
				throw new Error("退款申请不存在")
			}
			let order = await dbHelper.getById("t3ds-order", apply.orderSn)
			if (!order) {
				throw new Error("订单不存在")
			}
			order.refundApply = apply
			let refundFee = this.calcRefundFee({
				order,
				count: apply.count
			})
			Object.assign(order, refundFee)
			return order
		} catch (e) {
			throw e
		}
	}

	async getOrderNeedInvoice({
		memberId,
		type = 'goods',
		pageNum = 1,
		pageSize = 10,
		keyword,
		createStartTime,
		createEndTime
	}) {
		let dbCmd = this.db.command
		let $ = dbCmd.aggregate
		let result = {
			total: 0,
			list: []
		}
		try {
			var query = [{
				type: dbCmd.eq(type),
				status: dbCmd.in([4, 5]),
				is_invoice: dbCmd.exists(false).or(dbCmd.eq(false))
			}]

			if (createStartTime && createEndTime) {
				query.push({
					create_time: dbCmd.and(dbCmd.gte(createStartTime), dbCmd.lte(createEndTime))
				})
			}

			if (memberId) {
				query.push({
					user_id: memberId
				})
			}
			query = dbCmd.and(query)
			if (pageNum == 1) {
				let countRes = await this.db.collection("t3ds-order").where(query).count()
				if (!countRes.total) {
					return result
				}
				result.total = countRes.total
			}
			let coll = this.db.collection("t3ds-order").aggregate()
				.match(query)
				.sort({
					'pay_time': -1,
					'create_time': -1
				})
				.skip((pageNum - 1) * pageSize)
				.limit(pageSize)
				.unwind("$items")
				.lookup({
					from: "uni-id-users",
					let: {
						id: "$user_id"
					},
					pipeline: $.pipeline()
						.match(dbCmd.expr($.and([
							$.eq(["$_id", "$$id"])
						])))
						.project({
							nickname: 1,
							mobile: 1,
							id: 1
						})
						.done(),
					as: "memberInfo"
				})
			if (type == 'subscribe') {
				coll.lookup({
						from: "t3ds-script",
						let: {
							id: "$items.script_id",
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$_id", "$$id"])
							])))
							.project({
								name: 1,
								cover: 1,
							})
							.done(),
						as: "scriptInfo",
					})
					.lookup({
						from: "t3ds-subscribe-motorcade",
						let: {
							id: "$motorcadeId",
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$_id", "$$id"])
							])))
							.project({
								name: 1,
								roomId: 1,
								storeName: 1,
								roomName: 1,
								startTime: 1,
								endTime: 1
							})
							.done(),
						as: "motorcadeInfo",
					})
			}
			let res = await coll
				.project({
					create_time: 1,
					items: 1,
					total_fee: 1,
					pay_time: 1,
					payment_fee: 1,
					discount_fee: 1,
					type: 1,
					use_balance: 1,
					memberInfo: $.arrayElemAt(["$memberInfo", 0]),
					motorcadeInfo: $.arrayElemAt(["$motorcadeInfo", 0]),
					scriptInfo: $.arrayElemAt(["$scriptInfo", 0])
				})
				.end()
			result.list = res.data
			return result
		} catch (e) {
			throw e
		}
	}

	async getGoodsOrderList({
		memberId,
		pageNum = 1,
		pageSize = 10,
		status,
		keyword,
		channel,
		city,
		createStartTime,
		createEndTime,
		applyInvoice
	}) {
		console.log('优享订单 ');
		let dbCmd = this.db.command
		let $ = dbCmd.aggregate
		let result = {
			total: 0,
			list: []
		}
		try {
			var query = [{
				type: dbCmd.eq('goods')
			}]

			if (createStartTime && createEndTime) {
				query.push({
					create_time: dbCmd.and(dbCmd.gte(createStartTime), dbCmd.lte(createEndTime))
				})
			}

			if (memberId) {
				query.push({
					user_id: memberId
				})
			} else {
				let isAdmin = await this.ctx.auth.role.some(role => {
					return role === 'admin'
				})
				if (!isAdmin) {
					let userRes = await this.db.collection("uni-id-users").doc(this.ctx.auth.uid).field({
						city: true
					}).get()
					city = userRes.data[0].city
				}
			}
			if (status && status !== 8) {
				if (applyInvoice) {
					query.push({
						status: dbCmd.in(status)
					})
				} else {
					query.push({
						status
					})
				}
			}
			if (applyInvoice) {
				query.push({
					is_invoice: dbCmd.or(dbCmd.exists(false), dbCmd.eq(false))
				})
			}
			if (channel) {
				if (channel === 'self') {
					query.push({
						channel: dbCmd.eq('self').or(dbCmd.exists(false))
					})
				} else {
					query.push({
						channel
					})
				}
			}
			if (city) {
				let merchantRes = await this.db.collection("uni-id-users").where({
						city,
						role: 'boss'
					})
					.field({
						_id: true
					})
					.get()
				let merchantIds = merchantRes.data.map(item => {
					return item._id
				})
				if (!merchantIds.length) {
					return result
				}
				let goodsRes = await this.db.collection("t3ds-mall-goods").where({
						uid: dbCmd.in(merchantIds)
					})
					.field({
						_id: true
					})
					.get()
				let goodsIds = goodsRes.data.map(item => {
					return item._id
				})
				if (!goodsIds.length) {
					return result
				}
				query.push({
					'items.goods_id': dbCmd.in(goodsIds)
				})
			}
			if (keyword) {
				if (/^[1][3,4,5,7,8,9][0-9]{9}$/.test(keyword)) {
					query.push({
						user_phone: keyword
					})
				} else if (/^\d+/.test(keyword)) {
					let member = await dbHelper.getOne("uni-id-users", {
						role: 'member',
						id: parseInt(keyword)
					})
					if (!member) {
						return {
							total: 0,
							list: []
						}
					}
					query.push({
						user_id: member._id
					})
				} else {
					query.push(dbCmd.or([{
						user_nickname: new RegExp(keyword)
					}, {
						'items.goods_name': new RegExp(keyword)
					}]))
				}
			}
			query = dbCmd.and(query)
			let statusDic = {
				'WAITING': 6,
				'REFUNDING': 7,
				'REFUNDED': 8,
				'REJECTED': 10
			}
			if (status === 8) {
				if (pageNum == 1) {
					let countRes = await this.db.collection("t3ds-refund-apply").aggregate()
						.lookup({
							from: "t3ds-order",
							localField: "orderSn",
							foreignField: "_id",
							as: "order"
						})
						.unwind("$order")
						.replaceRoot({
							newRoot: "$order"
						})
						.match(query)
						.count("count")
						.end()
					if (!countRes.data || !countRes.data.length || !countRes.data[0].count) {
						return result
					}
					result.total = countRes.data[0].count
				}
				let res = await this.db.collection("t3ds-refund-apply").aggregate()
					.sort({
						'createTime': -1
					})
					.lookup({
						from: "t3ds-order",
						localField: "orderSn",
						foreignField: "_id",
						as: "order"
					})
					.unwind("$order")
					.project({
						apply: {
							refundApply: {
								_id: "$_id",
								createTime: "$createTime",
								reason: "$reason",
								count: "$count",
								status: "$status",
								rejectReason: "$rejectReason"
							},
						},
						order: "$order"
					})
					.project({
						mergeObj: $.mergeObjects(["$order", "$apply"])
					})
					.replaceRoot({
						newRoot: "$mergeObj"
					})
					.match(query)
					.skip((pageNum - 1) * pageSize)
					.limit(pageSize)
					.lookup({
						from: "uni-id-users",
						localField: "user_id",
						foreignField: "_id",
						as: "member"
					})
					.lookup({
						from: "t3ds-ticket-code",
						let: {
							"orderId": "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderId", "$$orderId"])
							])))
							.done(),
						as: 'tickets'
					})
					.lookup({
						from: "t3ds-receipts",
						let: {
							"orderId": "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderId", "$$orderId"])
							])))
							.done(),
						as: 'receipts'
					})
					.end()
				res.data.forEach(item => {
					item.status = statusDic[item.refundApply.status]
					let refundFee = this.calcRefundFee({
						order: item,
						count: item.refundApply.count
					})
					Object.assign(item, refundFee)
					if (item.receipts && item.receipts.length) {
						item.hasReceipts = true
						delete item.hasReceipts
					} else {
						item.hasReceipts = false
					}
				})
				result.list = res.data
			} else if (!status) {
				if (pageNum == 1) {
					let countRes = await this.db.collection("t3ds-order").where(query).count()
					if (!countRes.total) {
						return result
					}
					result.total = countRes.total
				}
				let res = await this.db.collection("t3ds-order").aggregate()
					.match(query)
					.sort({
						'pay_time': -1,
						'create_time': -1
					})
					.skip((pageNum - 1) * pageSize)
					.limit(pageSize)
					.lookup({
						from: "uni-id-users",
						localField: "user_id",
						foreignField: "_id",
						as: "member"
					})
					.lookup({
						from: "t3ds-refund-apply",
						let: {
							orderId: "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderSn", "$$orderId"])
							])))
							.sort({
								createTime: -1
							})
							.done(),
						as: 'refundApplyList'
					})
					.lookup({
						from: "t3ds-ticket-code",
						let: {
							"orderId": "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderId", "$$orderId"])
							])))
							.done(),
						as: 'tickets'
					})
					.lookup({
						from: "t3ds-receipts",
						let: {
							"orderId": "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderId", "$$orderId"])
							])))
							.done(),
						as: 'receipts'
					})
					.end()
				res.data.forEach(item => {
					if (item.refundApplyList && item.refundApplyList.length) {
						var refundedCount = 0
						item.refundApplyList.forEach(apply => {
							if (apply.status !== 'REJECTED' && apply.status !== 'FAILED') {
								refundedCount += apply.count
							}
						})
						let apply = item.refundApplyList[0]
						if (refundedCount === item.items[0].count) {
							item.status = statusDic[apply.status]
						}
						item.refundedCount = refundedCount
						item.refundApply = apply
						delete item.refundApplyList
					} else {
						item.refundedCount = 0
					}
				})
				result.list = res.data
			} else {
				if (pageNum == 1) {
					let countRes = await this.db.collection("t3ds-order").where(query).count()
					if (!countRes.total) {
						return result
					}
					result.total = countRes.total
				}
				let res = await this.db.collection("t3ds-order").aggregate()
					.match(query)
					.sort({
						'pay_time': -1,
						'create_time': -1
					})
					.skip((pageNum - 1) * pageSize)
					.limit(pageSize)
					.lookup({
						from: "uni-id-users",
						localField: "user_id",
						foreignField: "_id",
						as: "member"
					})
					.lookup({
						from: "t3ds-ticket-code",
						let: {
							"orderId": "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderId", "$$orderId"])
							])))
							.done(),
						as: 'tickets'
					})
					.lookup({
						from: "t3ds-receipts",
						let: {
							"orderId": "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderId", "$$orderId"])
							])))
							.done(),
						as: 'receipts'
					})
					.end()
				result.list = res.data
			}
			for (var i = 0; i < result.list.length; i++) {
				let order = result.list[i]
				let tickets = order.tickets || []
				let chargeoffTime
				let t = tickets.filter(item => {
					return item.chargeoffTime && item.chargeoffTime > 0
				})
				t.sort((a, b) => {
					return a - b
				})
				if (t.length) {
					chargeoffTime = t[0].chargeoffTime
				}
				if (chargeoffTime) {
					order.chargeoffTime = chargeoffTime
				} else if (tickets.length) {
					order.deadline = tickets[0].deadline
				}
				if (order.member.length) {
					order.memberId = order.member[0].id
				}
				delete order.member

				if (order.receipts && order.receipts.length) {
					order.hasReceipts = true
					delete order.receipts
				} else {
					order.hasReceipts = false
				}
			}
			return result
		} catch (e) {
			throw e
		}
	}

	// 获取预约订单列表
	async getSubscribeOrderList({
		memberId,
		pageNum = 1,
		pageSize = 10,
		status,
		keyword,
		channel,
		city,
		createStartTime,
		createEndTime,
		applyInvoice
	}) {
		const db = uniCloud.database()
		const dbCmd = db.command
		const $ = dbCmd.aggregate

		let result = {
			total: 0,
			list: []
		}
		try {
			var query = [{
				type: dbCmd.or(dbCmd.eq('subscribe'), dbCmd.eq('tearoom'))
			}]

			if (createStartTime && createEndTime) {
				query.push({
					create_time: dbCmd.and(dbCmd.gte(createStartTime), dbCmd.lte(createEndTime))
				})
			}

			if (memberId) {
				query.push({
					user_id: memberId
				})
			} else {
				let isAdmin = await this.ctx.auth.role.some(role => {
					return role === 'admin'
				})
				if (!isAdmin) {
					let userRes = await this.db.collection("uni-id-users").doc(this.ctx.auth.uid).field({
						city: true
					}).get()
					city = userRes.data[0].city
				}
			}
			if (status && status !== 8) {
				if (applyInvoice) {
					query.push({
						status: dbCmd.in(status)
					})
				} else {
					query.push({
						status
					})
				}
			}
			if (applyInvoice) {
				query.push({
					is_invoice: dbCmd.or(dbCmd.exists(false), dbCmd.eq(false))
				})
			}
			if (channel) {
				if (channel === 'self') {
					query.push({
						channel: dbCmd.eq('self').or(dbCmd.exists(false))
					})
				} else {
					query.push({
						channel
					})
				}
			}
			if (city) {
				let merchantRes = await this.db.collection("uni-id-users").where({
						city,
						role: 'boss'
					})
					.field({
						_id: true
					})
					.get()
				let merchantIds = merchantRes.data.map(item => {
					return item._id
				})
				if (!merchantIds.length) {
					return result
				}
				let storeRes = await this.db.collection("t3ds-store").where({
						uid: dbCmd.in(merchantIds)
					})
					.field({
						_id: true
					})
					.get()
				let storeIds = storeRes.data.map(item => {
					return item._id
				})
				if (!storeIds.length) {
					return result
				}
				query.push({
					'store_id': dbCmd.in(storeIds)
				})
			}
			if (keyword) {
				if (/^[1][3,4,5,7,8,9][0-9]{9}$/.test(keyword)) {
					query.push({
						user_phone: keyword
					})
				} else if (/^\d+/.test(keyword)) {
					let member = await dbHelper.getOne("uni-id-users", {
						role: 'member',
						id: parseInt(keyword)
					})
					if (!member) {
						return {
							total: 0,
							list: []
						}
					}
					query.push({
						user_id: member._id
					})
				} else {
					query.push(dbCmd.or([{
						user_nickname: new RegExp(keyword)
					}, {
						'items.script_name': new RegExp(keyword)
					}]))
				}
			}
			query = dbCmd.and(query)
			let statusDic = {
				'WAITING': 6,
				'REFUNDING': 7,
				'REFUNDED': 8,
				'REJECTED': 10
			}
			if (status === 8) {
				if (pageNum == 1) {
					let countRes = await this.db.collection("t3ds-refund-apply").aggregate()
						.lookup({
							from: "t3ds-order",
							localField: "orderSn",
							foreignField: "_id",
							as: "order"
						})
						.unwind("$order")
						.replaceRoot({
							newRoot: "$order"
						})
						.match(query)
						.count("count")
						.end()
					if (!countRes.data || !countRes.data.length || !countRes.data[0].count) {
						return result
					}
					result.total = countRes.data[0].count
				}
				let res = await this.db.collection("t3ds-refund-apply").aggregate()
					.sort({
						'create_time': -1,
						'pay_time': -1,
					})
					.lookup({
						from: "t3ds-order",
						localField: "orderSn",
						foreignField: "_id",
						as: "order"
					})
					.unwind("$order")
					.project({
						apply: {
							refundApply: {
								_id: "$_id",
								createTime: "$createTime",
								reason: "$reason",
								count: "$count",
								status: "$status",
								rejectReason: "$rejectReason"
							},
						},
						order: "$order"
					})
					.project({
						mergeObj: $.mergeObjects(["$order", "$apply"])
					})
					.replaceRoot({
						newRoot: "$mergeObj"
					})
					.match(query)
					.skip((pageNum - 1) * pageSize)
					.limit(pageSize)
					.addFields({
						items0: $.arrayElemAt(['$items', 0])
					})
					.lookup({
						from: "t3ds-subscribe-motorcade",
						let: {
							motorcadeId: '$motorcadeId'
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.eq(['$_id', '$$motorcadeId'])))
							.project({
								name: 1,
								storeName: 1,
								roomName: 1,
								roomId: 1,
								orderIds: 1,
								startTime: 1,
								endTime: 1,
								initiator: 1,
								costPerPerson: 1,
								maxPlayers: 1,
								minPlayers: 1,
								currentMaleCount: 1,
								currentFemaleCount: 1,
								status: 1,
								renewalOrders: 1
							})
							.done(),
						as: 'motorcade'
					})
					.unwind({
						path: '$motorcade',
						preserveNullAndEmptyArrays: true
					})
					.lookup({
						from: 't3ds-store',
						let: {
							storeId: '$items0.store_id'
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.eq(['$_id', '$$storeId'])))
							.project({
								storeName: 1,
								location: 1,
								address: 1,
								phone: 1,
								cooperationMode: 1
							})
							.done(),
						as: 'store',
					})
					.lookup({
						from: 't3ds-store-room',
						let: {
							roomId: '$items0.room_id'
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.eq(['$_id', '$$roomId'])))
							.project({
								name: 1,
								photos: 1
							})
							.done(),
						as: 'room',
					})
					.lookup({
						from: 't3ds-script',
						let: {
							scriptId: '$items0.script_id'
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.eq(['$_id', '$$scriptId'])))
							.project({
								name: 1,
								cover: 1,
								playTime: 1,
								difficulty: 1,
								standardPlayers: 1,
								simpleTag: 1
							})
							.done(),
						as: 'script',
					})
					.unwind({
						path: '$store',
						preserveNullAndEmptyArrays: true
					})
					.unwind({
						path: '$room',
						preserveNullAndEmptyArrays: true
					})
					.unwind({
						path: '$script',
						preserveNullAndEmptyArrays: true
					})
					.end()
				res.data.forEach(item => {
					item.status = statusDic[item.refundApply.status]
					let refundFee = this.calcRefundFee({
						order: item,
						count: item.refundApply.count
					})
					Object.assign(item, refundFee)
					if (item.receipts && item.receipts.length) {
						item.hasReceipts = true
						delete item.hasReceipts
					} else {
						item.hasReceipts = false
					}
				})
				// console.log("res.data: ", res.data);
				result.list = res.data
			} else if (!status) {
				if (pageNum == 1) {
					let total = await getSubscribeOrderData('total', query)
					if (!total) {
						return result
					}
					result.total = total
				}
				let res = await getSubscribeOrderData('list', query, pageNum, pageSize)
				res.data.forEach(item => {
					if (item.status === 3 && item.type == 'subscribe' && item.motorcade.endTime < Date
						.now()) {
						item.status = 9
					}
					if (item.refundApplyList && item.refundApplyList.length) {
						var refundedCount = 0
						item.refundApplyList.forEach(apply => {
							if (apply.status !== 'REJECTED' && apply.status !== 'FAILED') {
								refundedCount += apply.count
							}
						})
						let apply = item.refundApplyList[0]
						if (refundedCount === item.items[0].count) {
							item.status = statusDic[apply.status]
						}
						item.refundedCount = refundedCount
						item.refundApply = apply
						delete item.refundApplyList
					} else {
						item.refundedCount = 0
					}
				})
				result.list = res.data
			} else {
				if (pageNum == 1) {
					let total = await getSubscribeOrderData('total', query)
					if (!total) {
						return result
					}
					result.total = total
				}
				let res = await getSubscribeOrderData('list', query, pageNum, pageSize)
				let findIndex = res.data.findIndex(item => item.status === 3 && item.motorcade && item.motorcade
					.endTime < Date
					.now())
				if (findIndex !== -1) {
					res.data.splice(findIndex, 1)
					result.total--
				}

				if (!result.total) {
					return result
				}
				result.list = res.data
			}

			for (var i = 0; i < result.list.length; i++) {
				let order = result.list[i]
				delete order.items0
				// if (order.member && order.member.length) {
				// 	order.memberId = order.member[0].id
				// }

				// 预约剧本杀订单
				if (order.type == 'subscribe') {
					// console.log('预约剧本杀订单');
					let items = order.items[0]
					let room = order.room || {}
					let store = order.store || {}
					let script = order.script || {}
					let motorcade = order.motorcade || {}

					items.count = (items.maleCount || 0) + (items.femaleCount || 0)

					order.roomInfo = {
						roomId: room._id || '',
						roomName: room.name || '',
						price: items.room_price || store.unifyPrice,
						storeId: store._id,
						storeName: store.name,
						address: store.address,
						location: store.location,
						cooperationMode: store.cooperationMode
					}

					order.scriptInfo = {
						_id: script._id,
						name: script.name,
						cover: script.cover,
						storyTags: script.storyTags,
						classTags: script.classTags,
						price: items.script_price,
						playTime: script.playTime,
						difficulty: script.difficulty,
						simpleTag: script.simpleTag,
						standardPlayers: script.standardPlayers
					}

					order.motorcadeInfo = motorcade

					order.shareBrokerage = script.shareBrokerage
					if (!script.shareBrokerage) {
						let {
							value
						} = await dbHelper.getOne("t3ds-system-config", {
							key: 'shareBrokerage'
						})
						order.shareBrokerage = value / 100
					}

					// 获取车队成员头像
					let memberRes = await db.collection('t3ds-order').aggregate()
						.match({
							_id: dbCmd.in(motorcade.orderIds)
						})
						.lookup({
							from: 'uni-id-users',
							localField: 'user_id',
							foreignField: '_id',
							as: 'member'
						})
						.unwind('$member')
						.replaceRoot({
							newRoot: '$member'
						})
						.project({
							id: 1,
							avatar: 1
						})
						.end()
					let obj = {}
					memberRes.data = memberRes.data.reduce(function(item, next) {
						obj[next._id] ? '' : obj[next._id] = true && item.push(next)
						return item
					}, [])
					let initiatorRes = {}
					for (let i = 0; i < memberRes.data.length; i++) {
						if (memberRes.data[i].id === motorcade.initiator) {
							initiatorRes = memberRes.data[i]
							memberRes.data.splice(i, 1)
							break
						}
					}
					memberRes.data.unshift(initiatorRes)
					order.members = memberRes.data

					// console.log("motorcade: ",motorcade, motorcade.renewalOrders.length);
					// 存在续时
					if (motorcade.renewalOrders && motorcade.renewalOrders.length > 0) {
						// console.log('预约剧本杀订单存在续时');
						// 当前预约订单最新的关联续时订单数据
						let renewalOrderId = motorcade.renewalOrders[0].renewalOrdersId.filter(item => item
							.subscribeOrderId === order._id)[0].renewalOrderId
						let renewalOrderRes = await dbHelper.getById("t3ds-order", renewalOrderId)
						order.renewalData = {
							renewalOrderId, // 最新续时订单id
							endTime: motorcade.renewalOrders[0].renewalEndTime, // 最新续时订单结束时间
							duration: motorcade.renewalOrders[0].renewalDuration, // 最新续时时长
							status: renewalOrderRes.status // 续时订单状态
						}

						// 续时订单金额
						for (let i = 0; i < motorcade.renewalOrders.length; i++) {
							let item = motorcade.renewalOrders[i]
							for (let j = 0; j < item.renewalOrdersId.length; j++) {
								let item2 = item.renewalOrdersId[j]
								if (item2.subscribeOrderId === order._id) {
									let res = await dbHelper.getById("t3ds-order", item2
										.renewalOrderId) // 当前订单的续时订单id
									item.money = (res.total_fee || 0) - (res.discount_fee || 0)
								}
							}
						}

						// 续时订单数组-按倒序排，用于在界面上显示所有续时记录
						motorcade.renewalOrders_inverted = JSON.parse(JSON.stringify(motorcade.renewalOrders))
							.reverse()
						if (renewalOrderRes.status !== 2) {
							motorcade.renewalOrders_inverted.pop()
						}

						// 续时订单是否未全部支付
						// let notPaidInFull = false // 已全部支付
						// for (let item of motorcade.renewalOrders[0].renewalOrdersId) {
						//   let count = await dbHelper.getCount('t3ds-order', {
						//     _id: item.renewalOrderId,
						//     status: dbCmd.or(dbCmd.eq(1), dbCmd.eq(-1))
						//   })
						//   if (count > 0) { // 存在未支付的
						//     notPaidInFull = true
						//     break
						//   }
						// }
						// motorcade.renewalOrders[0].notPaidInFull = notPaidInFull
						// await dbHelper.update("t3ds-subscribe-motorcade", {
						//   _id: motorcade._id,
						//   ['renewalOrders.' + 0]: {
						//     notPaidInFull
						//   }
						// });

						// 订单实付
						let renewalOrdersId = motorcade.renewalOrders.map(item => {
							return item.renewalOrdersId.filter(item => item.subscribeOrderId === order
								._id)[0].renewalOrderId
						})
						// console.log("renewalOrders: ",renewalOrdersId);
						for (let id of renewalOrdersId) {
							let res = await db.collection('t3ds-order')
								.where({
									_id: id,
									status: 2
								})
								.field({
									total_fee: true,
									discount_fee: true
								})
								.get()
							if (res.data[0] && res.data[0].total_fee) {
								order.total_fee += res.data[0].total_fee - (res.data[0].discount_fee || 0)
							}
						}
					}

					// delete order.member
					delete order.room
					delete order.store
					delete order.script
					delete order.motorcade
				}

				// 预约茶室订单
				if (order.type == 'tearoom') {
					// console.log('预约茶室订单');
					let items = order.items[0]
					let room = order.room || {}
					let store = order.store || {}

					order.roomInfo = {
						roomId: room._id || '',
						roomName: room.name || '',
						photos: room.photos ? room.photos[0] : '',
						storeId: store._id,
						storeName: store.name,
						address: store.address,
						location: store.location,
						price: items.room_price || store.unifyPrice,
						cooperationMode: store.cooperationMode
					}

					// 存在续时
					if (order.renewalOrders && order.renewalOrders.length > 0) {
						// console.log('预约茶室订单存在续时');
						// 最新的关联续时订单数据
						let renewalOrderId = order.renewalOrders[0].renewalOrderId
						let renewalOrderRes = await dbHelper.getById("t3ds-order", renewalOrderId)
						order.renewalData = {
							renewalOrderId, // 最新续时订单id
							endTime: order.renewalOrders[0].renewalEndTime, // 最新续时订单结束时间
							duration: order.renewalOrders[0].renewalDuration, // 最新续时时长
							status: renewalOrderRes.status // 续时订单状态
						}

						// 续时订单金额
						for (let i = 0; i < order.renewalOrders.length; i++) {
							let res = await dbHelper.getById("t3ds-order", order.renewalOrders[i]
								.renewalOrderId) // 当前订单的续时订单id
							order.renewalOrders[i].money = (res.total_fee || 0) - (res.discount_fee || 0)
						}

						// 续时订单数组-按倒序排，用于在界面上显示所有续时记录
						order.renewalOrders_inverted = JSON.parse(JSON.stringify(order.renewalOrders)).reverse()
						if (renewalOrderRes.status === 1) {
							order.renewalOrders_inverted.pop()
						}

						// 订单实付
						let renewalOrdersId = order.renewalOrders.map(item => item.renewalOrderId)
						for (let id of renewalOrdersId) {
							let res = await db.collection('t3ds-order')
								.where({
									_id: id,
									status: 3
								})
								.field({
									total_fee: true,
									discount_fee: true
								})
								.get()
							if (res.data[0] && res.data[0].total_fee) {
								order.total_fee += res.data[0].total_fee - (res.data[0].discount_fee || 0)
							}
						}
					}
				}
			}
			return result
		} catch (e) {
			console.error(e);
			throw e
		}
	}

	async getOrderList({
		memberId,
		pageNum = 1,
		pageSize = 10,
		status,
		keyword,
		channel,
		city
	}) {
		let dbCmd = this.db.command
		let $ = dbCmd.aggregate
		let result = {
			total: 0,
			list: []
		}
		try {
			var query = [{
				type: dbCmd.eq('goods').or(dbCmd.eq('subscribe'))
			}]
			if (memberId) {
				query.push({
					user_id: memberId
				})
			} else {
				let isAdmin = await this.ctx.auth.role.some(role => {
					return role === 'admin'
				})
				if (!isAdmin) {
					let userRes = await this.db.collection("uni-id-users").doc(this.ctx.auth.uid).field({
						city: true
					}).get()
					city = userRes.data[0].city
				}
			}
			if (status && status !== 8) {
				query.push({
					status
				})
			}
			if (channel) {
				if (channel === 'self') {
					query.push({
						channel: dbCmd.eq('self').or(dbCmd.exists(false))
					})
				} else {
					query.push({
						channel
					})
				}
			}
			if (city) {
				let merchantRes = await this.db.collection("uni-id-users").where({
						city,
						role: 'boss'
					})
					.field({
						_id: true
					})
					.get()
				let merchantIds = merchantRes.data.map(item => {
					return item._id
				})
				if (!merchantIds.length) {
					return result
				}
				let goodsRes = await this.db.collection("t3ds-mall-goods").where({
						uid: dbCmd.in(merchantIds)
					})
					.field({
						_id: true
					})
					.get()
				let goodsIds = goodsRes.data.map(item => {
					return item._id
				})
				if (!goodsIds.length) {
					return result
				}
				query.push({
					'items.goods_id': dbCmd.in(goodsIds)
				})
			}
			if (keyword) {
				if (/^[1][3,4,5,7,8,9][0-9]{9}$/.test(keyword)) {
					query.push({
						user_phone: keyword
					})
				} else if (/^\d+/.test(keyword)) {
					let member = await dbHelper.getOne("uni-id-users", {
						role: 'member',
						id: parseInt(keyword)
					})
					if (!member) {
						return {
							total: 0,
							list: []
						}
					}
					query.push({
						user_id: member._id
					})
				} else {
					query.push(dbCmd.or([{
						user_nickname: new RegExp(keyword)
					}, {
						'items.goods_name': new RegExp(keyword)
					}]))
				}
			}
			query = dbCmd.and(query)
			let statusDic = {
				'WAITING': 6,
				'REFUNDING': 7,
				'REFUNDED': 8,
				'REJECTED': 10
			}
			if (status === 8) {
				if (pageNum == 1) {
					let countRes = await this.db.collection("t3ds-refund-apply").aggregate()
						.lookup({
							from: "t3ds-order",
							localField: "orderSn",
							foreignField: "_id",
							as: "order"
						})
						.unwind("$order")
						.replaceRoot({
							newRoot: "$order"
						})
						.match(query)
						.count("count")
						.end()
					if (!countRes.data || !countRes.data.length || !countRes.data[0].count) {
						return result
					}
					result.total = countRes.data[0].count
				}
				let res = await this.db.collection("t3ds-refund-apply").aggregate()
					.sort({
						'createTime': -1
					})
					.lookup({
						from: "t3ds-order",
						localField: "orderSn",
						foreignField: "_id",
						as: "order"
					})
					.unwind("$order")
					.project({
						apply: {
							refundApply: {
								_id: "$_id",
								createTime: "$createTime",
								reason: "$reason",
								count: "$count",
								status: "$status",
								rejectReason: "$rejectReason"
							},
						},
						order: "$order"
					})
					.project({
						mergeObj: $.mergeObjects(["$order", "$apply"])
					})
					.replaceRoot({
						newRoot: "$mergeObj"
					})
					.match(query)
					.skip((pageNum - 1) * pageSize)
					.limit(pageSize)
					.lookup({
						from: "uni-id-users",
						localField: "user_id",
						foreignField: "_id",
						as: "member"
					})
					.lookup({
						from: "t3ds-ticket-code",
						let: {
							"orderId": "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderId", "$$orderId"])
							])))
							.done(),
						as: 'tickets'
					})
					.lookup({
						from: "t3ds-receipts",
						let: {
							"orderId": "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderId", "$$orderId"])
							])))
							.done(),
						as: 'receipts'
					})
					.end()
				res.data.forEach(item => {
					item.status = statusDic[item.refundApply.status]
					let refundFee = this.calcRefundFee({
						order: item,
						count: item.refundApply.count
					})
					Object.assign(item, refundFee)
					if (item.receipts && item.receipts.length) {
						item.hasReceipts = true
						delete item.hasReceipts
					} else {
						item.hasReceipts = false
					}
				})
				result.list = res.data
			} else if (!status) {
				console.log('query', query)
				if (pageNum == 1) {
					let countRes = await this.db.collection("t3ds-order").where(query).count()
					if (!countRes.total) {
						return result
					}
					result.total = countRes.total
				}
				let res = await await this.db.collection("t3ds-order").aggregate()
					.match(query)
					.sort({
						'pay_time': -1,
						'create_time': -1
					})
					.skip((pageNum - 1) * pageSize)
					.limit(pageSize)
					.lookup({
						from: "uni-id-users",
						localField: "user_id",
						foreignField: "_id",
						as: "member"
					})
					.lookup({
						from: "t3ds-refund-apply",
						let: {
							orderId: "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderSn", "$$orderId"])
							])))
							.sort({
								createTime: -1
							})
							.done(),
						as: 'refundApplyList'
					})
					.lookup({
						from: "t3ds-ticket-code",
						let: {
							"orderId": "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderId", "$$orderId"])
							])))
							.done(),
						as: 'tickets'
					})
					.lookup({
						from: "t3ds-receipts",
						let: {
							"orderId": "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderId", "$$orderId"])
							])))
							.done(),
						as: 'receipts'
					})
					.end()
				res.data.forEach(item => {
					if (item.refundApplyList && item.refundApplyList.length) {
						var refundedCount = 0
						item.refundApplyList.forEach(apply => {
							if (apply.status !== 'REJECTED' && apply.status !== 'FAILED') {
								refundedCount += apply.count
							}
						})
						let apply = item.refundApplyList[0]
						if (refundedCount === item.items[0].count) {
							item.status = statusDic[apply.status]
						}
						item.refundedCount = refundedCount
						item.refundApply = apply
						delete item.refundApplyList
					} else {
						item.refundedCount = 0
					}
				})
				result.list = res.data
			} else {
				if (pageNum == 1) {
					let countRes = await this.db.collection("t3ds-order").where(query).count()
					if (!countRes.total) {
						return result
					}
					result.total = countRes.total
				}
				let res = await this.db.collection("t3ds-order").aggregate()
					.match(query)
					.sort({
						'pay_time': -1,
						'create_time': -1
					})
					.skip((pageNum - 1) * pageSize)
					.limit(pageSize)
					.lookup({
						from: "uni-id-users",
						localField: "user_id",
						foreignField: "_id",
						as: "member"
					})
					.lookup({
						from: "t3ds-ticket-code",
						let: {
							"orderId": "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderId", "$$orderId"])
							])))
							.done(),
						as: 'tickets'
					})
					.lookup({
						from: "t3ds-receipts",
						let: {
							"orderId": "$_id"
						},
						pipeline: $.pipeline()
							.match(dbCmd.expr($.and([
								$.eq(["$orderId", "$$orderId"])
							])))
							.done(),
						as: 'receipts'
					})
					.end()
				result.list = res.data
			}
			for (var i = 0; i < result.list.length; i++) {
				let order = result.list[i]
				let tickets = order.tickets || []
				let chargeoffTime
				let t = tickets.filter(item => {
					return item.chargeoffTime && item.chargeoffTime > 0
				})
				t.sort((a, b) => {
					return a - b
				})
				if (t.length) {
					chargeoffTime = t[0].chargeoffTime
				}
				if (chargeoffTime) {
					order.chargeoffTime = chargeoffTime
				} else if (tickets.length) {
					order.deadline = tickets[0].deadline
				}
				if (order.member.length) {
					order.memberId = order.member[0].id
				}
				delete order.member

				if (order.receipts && order.receipts.length) {
					order.hasReceipts = true
					delete order.receipts
				} else {
					order.hasReceipts = false
				}

				// 预约订单
				if (order.type == 'subscribe') {
					let item = order.items[0]

					let room = {}
					if (item.room_id) {
						room = await dbHelper.getById("t3ds-store-room", item.room_id)
					}
					let store = await dbHelper.getById("t3ds-store", item.store_id)

					order.roomInfo = {
						roomId: room._id || '',
						roomName: room.name || '',
						storeId: store._id,
						storeName: store.name,
						address: store.address,
						location: store.location,
						price: order.items[0].room_price || store.unifyPrice,
						cooperationMode: store.cooperationMode
					}

					let script = await dbHelper.getById("t3ds-script", item.script_id)
					order.scriptInfo = {
						_id: script._id,
						name: script.name,
						cover: script.cover,
						storyTags: script.storyTags,
						classTags: script.classTags,
						price: order.items[0].script_price,
						playTime: script.playTime,
						difficulty: script.difficulty,
						simpleTag: script.simpleTag,
						standardPlayers: script.standardPlayers
					}

					let motorcade = await dbHelper.getById("t3ds-subscribe-motorcade", order.motorcadeId)
					order.motorcadeInfo = motorcade
				}
			}
			return result
		} catch (e) {
			throw e
		}
	}

	async getReceiptList({
		uid,
		orderId,
		ticketId,
		storeId,
		giftId,
		name,
		startDate,
		endDate,
		status,
		employeeId,
		pageNum = 1,
		pageSize = 10
	}) {
		let dbCmd = this.db.command
		try {
			var query = []
			if (uid) {
				query.push({
					uid
				})
			}
			if (ticketId) {
				query.push({
					ticketId
				})
			}
			if (orderId) {
				query.push({
					orderId
				})
			}
			if (giftId) {
				query.push({
					giftId
				})
			}
			let isBoss = this.ctx.auth.role.some(role => {
				return role === 'boss'
			})
			let isEmployee = this.ctx.auth.role.some(role => {
				return role === 'employee' || role === 'employee_2'
			})
			if (storeId) {
				query.push({
					storeId
				})
			} else {
				if (isBoss) {
					let stores = await dbHelper.getList("t3ds-store", {
						uid: this.ctx.auth.uid
					})
					query.push({
						storeId: dbCmd.in(stores.map(s => {
							return s._id
						}))
					})
				}
			}
			if (isEmployee) {
				query.push({
					employeeId: this.ctx.auth.uid
				})
			}
			if (name && name != '全部') {
				query.push({
					name
				})
			}
			if (status != null) {
				if (status === 0) {
					query.push({
						status: 0
					})
					query.push({
						deadline: dbCmd.gte(Date.now())
					})
				} else if (status === 2) {
					query.push(dbCmd.or({
						status: 2
					}, dbCmd.and([{
						deadline: dbCmd.lte(Date.now())
					}, {
						status: dbCmd.neq(1)
					}])))
				} else {
					query.push({
						status
					})
				}
			}
			if (startDate && endDate) {
				query.push({
					chargeoffTime: dbCmd.gte(startDate).and(dbCmd.lte(endDate))
				})
			} else if (startDate) {
				query.push({
					chargeoffTime: dbCmd.gte(startDate)
				})
			} else if (endDate) {
				query.push({
					chargeoffTime: dbCmd.lte(endDate)
				})
			}
			if (employeeId) {
				query.push({
					employeeId
				})
			}
			query = dbCmd.and(query)
			let result = {
				total: 0,
				list: []
			}
			console.log('query', query)
			let total = await dbHelper.getCount("t3ds-receipts", query)
			if (!total) {
				return result
			}
			result.total = total
			let res = await this.db.collection("t3ds-receipts").aggregate()
				.match(query)
				.sort({
					chargeoffTime: -1,
					deadline: 1
				})
				.skip((pageNum - 1) * pageSize)
				.limit(pageSize)
				.lookup({
					from: "uni-id-users",
					localField: "uid",
					foreignField: "_id",
					as: "member"
				})
				.end()
			res.data.forEach(item => {
				if (item.member && item.member.length) {
					item.memberId = item.member[0].id
					item.memberName = item.member[0].nickname
					delete item.member
				}
			})
			result.list = res.data
			return result
		} catch (e) {
			throw e
		}
	}

	async getReceiptNames({
		uid,
		storeId,
		giftId,
		ticketId,
		orderId,
	}) {
		let dbCmd = this.db.command
		let query = {}
		if (storeId) {
			query.storeId = storeId
		}
		if (uid) {
			query.uid = uid
		}
		if (giftId) {
			query.giftId = giftId
		}
		if (ticketId) {
			query.ticketId = ticketId
		} else if (orderId) {
			let ticketRes = await this.db.collection("t3ds-ticket-code").where({
					orderId
				})
				.field({
					_id: true
				})
				.get()
			let ticketIds = ticketRes.data.map(item => {
				return item._id
			})
			if (ticketIds.length) {
				query.ticketId = dbCmd.in(ticketIds)
			}
		}
		let res = await this.db.collection("t3ds-receipts").aggregate()
			.match(query)
			.group({
				_id: "$name"
			})
			.lookup({
				from: "t3ds-mall-sku",
				localField: "_id",
				foreignField: "receipts.name",
				as: "sku"
			})
			.project({
				_id: 1,
				'receipts': '$sku.receipts'
			})
			.end()
		return res.data.map(item => {
			let name = item._id
			let introduces = ''
			for (var i = 0; i < item.receipts.length; i++) {
				let r = item.receipts[i]
				for (var j = 0; j < r.length; j++) {
					let t = r[j]
					if (t.name == name) {
						introduces = t.introduces
						break
					}
				}
			}
			return {
				name,
				introduces
			}
		})
	}

	async prolongOrder({
		orderId,
		targetDate
	}) {
		let transaction = await this.db.startTransaction()
		try {
			let order = await dbHelper.getById("t3ds-order", orderId, transaction)
			if (!order) {
				throw new Error("订单不存在")
			}
			if (order.status !== 3 && order.status !== 9) {
				throw new Error("订单状态不对")
			}
			let dbCmd = this.db.command
			let tickets = await dbHelper.getList("t3ds-ticket-code", {
				orderId,
				status: dbCmd.neq(1)
			})
			for (var i = 0; i < tickets.length; i++) {
				let t = tickets[i]
				if (t.deadline >= targetDate) {
					throw new Error("时间不能小于等于当前的过期时间")
				}
				await transaction.collection("t3ds-ticket-code").doc(t._id).update({
					status: 0,
					deadline: targetDate
				})
			}
			let user = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
			let action = {
				time: Date.now(),
				by: user.username,
				desc: '延长过期时间'
			}
			if (!order.modify_history) {
				await dbHelper.update("t3ds-order", {
					_id: orderId,
					status: 3,
					update_time: Date.now(),
					update_by: user.username,
					modify_history: [action]
				}, transaction)
			} else {
				await dbHelper.update("t3ds-order", {
					_id: orderId,
					status: 3,
					update_time: Date.now(),
					update_by: user.username,
					['modify_history.' + order.modify_history.length]: action
				}, transaction)
			}
			await transaction.commit()
			order.status = 3
			return order
		} catch (e) {
			console.error("延长订单时间遇到错误", e)
			throw e
		}
	}

	async createEvaluation({
		orderId,
		score,
		description,
		photos = [],
		order = 1
	}) {
		let transaction = await this.db.startTransaction();
		try {
			let order = await dbHelper.getById("t3ds-order", orderId, transaction);
			if (!order) {
				await transaction.commit()
				throw new Error("订单不存在！")
			}
			if (order.status !== 4) {
				await transaction.commit()
				throw new Error("订单状态不正确！")
			}
			let member = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
			let eva = {}
			switch (order.type) {
				case 'goods': // 优享订单
					let goods = await dbHelper.getById("t3ds-mall-goods", order.items[0].goods_id);
					let merchant = await dbHelper.getById("uni-id-users", goods.uid)
					eva = {
						uid: this.ctx.auth.uid,
						orderId: orderId,
						goodsId: goods._id,
						goodsName: goods.name,
						merchantId: merchant.uid,
						merchantName: merchant.merchant_info.name,
						score: parseInt(score),
						photos,
						open: false,
						orderNum: 0,
						description: description,
						createBy: member.nickname,
						createTime: Date.now()
					}
					break;
				case 'subscribe': // 剧本杀订单
				case 'tearoom': // 茶室订单
					eva = {
						uid: this.ctx.auth.uid,
						orderId: orderId,
						score: parseInt(score),
						photos,
						open: false,
						orderNum: 0,
						description: description,
						createBy: member.nickname,
						createTime: Date.now()
					}
					break;
				default:
					break;
			}
			await dbHelper.insert("t3ds-mall-goods-evaluation", eva, transaction);

			order.status = 5;
			await dbHelper.update("t3ds-order", order, transaction);

			await transaction.commit();
		} catch (e) {
			console.error("评价订单遇到错误", e);
			await transaction.rollback();
			throw e
		}
	}

	async getStatisticsByTimeRange(city, data, timeRange) {
		let dbCmd = this.db.command
		let $ = dbCmd.aggregate
		let merchantRes = await this.db.collection("uni-id-users").where({
			city,
			role: 'boss'
		}).limit(1000).field({
			_id: true
		}).get()
		if (!merchantRes.data.length) {
			return data
		}
		let merchantIds = merchantRes.data.map(item => {
			return item._id
		})
		let goodsRes = await this.db.collection("t3ds-mall-goods").where({
			uid: dbCmd.in(merchantIds)
		}).limit(1000).field({
			_id: true
		}).get()
		if (!goodsRes.data.length) {
			return data
		}
		let goodsIds = goodsRes.data.map(item => {
			return item._id
		})
		let orderCollection = this.db.collection("t3ds-order")
		var countRes = await orderCollection.where({
			status: dbCmd.gt(2).and(dbCmd.lt(6)),
			pay_time: dbCmd.gte(timeRange.startTime).and(dbCmd.lte(timeRange.endTime)),
			type: 'goods',
			'items.settlement_price': dbCmd.exists(true),
			'items.goods_id': dbCmd.in(goodsIds)
		}).count();
		data.orderCount = countRes.total;
		// console.log("fill data", data, timeRange, countRes);
		if (countRes.total) {
			let salesRes = await orderCollection.aggregate()
				.match({
					status: dbCmd.gt(2).and(dbCmd.lt(6)),
					pay_time: dbCmd.gte(timeRange.startTime).and(dbCmd.lte(timeRange.endTime)),
					type: 'goods',
					'items.settlement_price': dbCmd.exists(true),
					'items.goods_id': dbCmd.in(goodsIds)
				})
				.group({
					_id: null,
					total: $.sum("$total_fee")
				})
				.end()
			data.sales = salesRes.data[0].total;
			let brokerageRes = await orderCollection.aggregate()
				.match({
					status: dbCmd.gt(2).and(dbCmd.lt(6)),
					pay_time: dbCmd.gte(timeRange.startTime).and(dbCmd.lte(timeRange.endTime)),
					type: 'goods',
					'items.settlement_price': dbCmd.exists(true),
					'items.goods_id': dbCmd.in(goodsIds)
				})
				.unwind("$items")
				.lookup({
					from: "t3ds-account-log",
					let: {
						orderId: "$_id"
					},
					pipeline: $.pipeline()
						.match(dbCmd.expr($.and([
							$.eq(["$orderId", "$$orderId"]),
							$.in(["$tradeType", [1, 2, 3, 4, 7, 8]])
						])))
						.group({
							_id: null,
							income: $.sum("$income")
						})
						.done(),
					as: "brokerageInfo"
				})
				// .lookup({
				// 	from: "t3ds-mall-sku",
				// 	let: {
				// 		skuId: "$items.sku_id"
				// 	},
				// 	pipeline: $.pipeline()
				// 		.match(dbCmd.expr($.eq(["$_id", "$$skuId"])))
				// 		.project({
				// 			"settlement_price": 1
				// 		})
				// 		.done(),
				// 	as: "settlementInfo"
				// })
				// .unwind("$settlementInfo")
				// .unwind("$brokerageInfo")
				.project({
					totalFee: "$total_fee",
					brokerageInfo: "$brokerageInfo",
					// brokerage: "$brokerageInfo.income",
					settlement: $.multiply(["$items.settlement_price", "$items.count"])
				})
				// .group({
				// 	_id: null,
				// 	brokerage: $.sum("$brokerage"),
				// 	settlement: $.sum("$settlement")
				// })
				.limit(999999)
				.end()
			// console.log('brokerageRes', brokerageRes)
			brokerageRes.data.forEach(item => {
				let brokerage = item.brokerageInfo.length ? item.brokerageInfo[0].income : 0
				data.brokerage += brokerage
				data.settlement += item.settlement
				// data.profit += (item.totalFee - item.settlement - brokerage)
			})
			// data.brokerage = brokerageRes.data.length ? brokerageRes.data[0].brokerage : 0;
			// data.settlement = brokerageRes.data.length ? brokerageRes.data[0].settlement : 0;
			data.profit = data.sales - data.brokerage - data.settlement;
		}
	}
	async getOrderStatistics({
		city
	}) {
		let result = {
			today: getData(),
			thisWeek: getData(),
			thisMonth: getData(),
			thisYear: getData()
		}
		//计算今日数据
		var timeRange = getTodayRange();
		await this.getStatisticsByTimeRange(city, result.today, timeRange);
		//计算本周数据
		timeRange = getThisWeekRange();
		await this.getStatisticsByTimeRange(city, result.thisWeek, timeRange);
		//计算本月数据
		timeRange = getThisMonthRange();
		await this.getStatisticsByTimeRange(city, result.thisMonth, timeRange);
		//计算今年数据
		timeRange = getThisYearRange();
		await this.getStatisticsByTimeRange(city, result.thisYear, timeRange);
		return result
	}
	async getTicketInfo({
		codeId
	}) {
		try {
			let ticket = await dbHelper.getById("t3ds-ticket-code", codeId)
			if (!ticket) {
				throw new Error("票券不存在！")
			}
			let otherTickets = await dbHelper.getList("t3ds-ticket-code", {
				orderId: ticket.orderId,
				status: 0,
				_id: this.db.command.neq(ticket._id)
			})
			return {
				...ticket,
				count: otherTickets.length + 1,
				otherTickets
			}
		} catch (e) {
			throw e
		}
	}
	async getReceiptInfo({
		codeId
	}) {
		try {
			let dbCmd = this.db.command
			let receipt = await dbHelper.getById("t3ds-receipts", codeId)
			if (!receipt) {
				throw new Error("小票不存在！")
			}
			let isBoss = this.ctx.auth.role.some(role => {
				return role === 'boss'
			})
			if (receipt.storeId) {
				let store = await dbHelper.getById("t3ds-store", receipt.storeId)
				if (isBoss) {
					if (store.uid != this.ctx.auth.uid) {
						throw new Error("无权限")
					}
				} else {
					if (store.employeeIds.indexOf(this.ctx.auth.uid) == -1) {
						throw new Error("无权限")
					}
				}
			}
			var maxCount = 0
			if (receipt.orderId) {
				maxCount = await dbHelper.getCount("t3ds-receipts", {
					orderId: receipt.orderId,
					status: 0,
					deadline: dbCmd.gte(Date.now()),
					name: receipt.name
				})
			} else if (receipt.giftId) {
				maxCount = await dbHelper.getCount("t3ds-receipts", {
					giftId: receipt.giftId,
					status: 0,
					deadline: dbCmd.gte(Date.now()),
					name: receipt.name
				})
			}
			return {
				...receipt,
				maxCount
			}
		} catch (e) {
			throw e
		}
	}
	//核销套票
	async chargeoffReceipt({
		codeId,
		storeId,
		count = 1
	}) {
		let dbCmd = this.db.command
		let transaction = await this.db.startTransaction()
		try {
			let receipt = await dbHelper.getById("t3ds-receipts", codeId, transaction)
			if (receipt == null) {
				throw new Error("小票不存在")
			}
			let isBoss = this.ctx.auth.role.some(role => {
				return role === 'boss'
			})
			if (receipt.storeId) {
				let store = await dbHelper.getById("t3ds-store", receipt.storeId)
				if (isBoss) {
					if (store.uid != this.ctx.auth.uid) {
						throw new Error("无权限")
					}
				} else {
					if (store.employeeIds.indexOf(this.ctx.auth.uid) == -1) {
						throw new Error("无权限")
					}
				}
			}
			if (receipt.status !== 0) {
				throw new Error("小票已使用或已过期")
			}
			if (receipt.deadline < Date.now()) {
				await this.db.collection("t3ds-receipts").doc(codeId).update({
					status: 2,
				})
				throw new Error("小票已过期")
			}
			let store = await dbHelper.getById("t3ds-store", storeId)
			if (!store) {
				throw new Error("门店不存在")
			}
			var list = []
			if (receipt.orderId) {
				let res = await this.db.collection("t3ds-receipts").where({
						orderId: receipt.orderId,
						status: 0,
						deadline: dbCmd.gte(Date.now()),
						name: receipt.name
					})
					.field({
						_id: true
					})
					.limit(count)
					.get()
				list = res.data
			} else if (receipt.giftId) {
				let res = await this.db.collection("t3ds-receipts").where({
						giftId: receipt.giftId,
						status: 0,
						deadline: dbCmd.gte(Date.now()),
						name: receipt.name
					})
					.field({
						_id: true
					})
					.limit(count)
					.get()
				list = res.data
			}
			if (count > list.length) {
				throw new Error("不能超过最大可使用数量")
			}
			let user = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
			for (var i = 0; i < list.length; i++) {
				let r = list[i]
				await transaction.collection("t3ds-receipts").doc(r._id).update({
					status: 1,
					storeId,
					storeName: store.name,
					employeeId: user._id,
					employeeName: user.username,
					chargeoffTime: Date.now()
				})
			}
			await transaction.commit()
		} catch (e) {
			console.log("核销遇到错误，codeId=", codeId, e);
			await transaction.rollback()
			throw e
		}
	}

	async chargeoffTicket({
		codeId,
		storeId
	}) {
		let transaction
		try {
			let user = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
			//门店
			let store = await dbHelper.getById("t3ds-store", storeId);
			if (!store) {
				return {
					code: 500,
					msg: "门店不存在"
				}
			}
			let isBoss = user.role.some(role => {
				return role === 'boss'
			})
			if (isBoss && store.uid !== user._id) {
				return {
					code: 500,
					msg: "无权限"
				}
			} else if (!isBoss && store.employeeIds.indexOf(user._id) === -1) {
				return {
					code: 500,
					msg: "无权限"
				}
			}
			transaction = await this.db.startTransaction()
			let code = await dbHelper.getById("t3ds-ticket-code", codeId, transaction);
			if (!code) {
				await transaction.commit()
				return {
					code: 500,
					msg: "券码不存在"
				}
			}
			if (code.status !== 0) {
				await transaction.commit()
				return {
					code: 500,
					msg: "券码已使用、已过期或已作废"
				}
			}
			let order = await dbHelper.getById("t3ds-order", code.orderId);
			let orderItem = order.items[0];
			let goods = await dbHelper.getById("t3ds-mall-goods", orderItem.goods_id);
			if (goods.uid !== store.uid) {
				await transaction.commit()
				return {
					code: 500,
					msg: "此商品不属于当前商家"
				}
			}
			if (goods.store_ids.length && goods.store_ids.indexOf(store._id) === -1) {
				await transaction.commit()
				return {
					code: 500,
					msg: "此商品不适用于本门店"
				}
			}

			if (code.deadline < Date.now()) {
				await transaction.collection("t3ds-ticket-code").doc(codeId).update({
					status: -1
				})
				await transaction.commit()
				return {
					code: 500,
					msg: "券码已过期"
				}
			}
			let sku = await dbHelper.getById("t3ds-mall-sku", orderItem.sku_id);
			let data = {
				status: 1,
				employeeId: user.id + "",
				employeeName: user.username,
				chargeoffTime: Date.now(),
				storeId: store._id,
				storeName: store.name
			}
			console.log("更新票券状态为已使用");
			await transaction.collection("t3ds-ticket-code").doc(codeId).update(data)
			let settlementPrice
			if (code.source === 'exchange') {
				let exchangeCode = await dbHelper.getById("t3ds-goods-exchange", code.exchangeCodeId)
				settlementPrice = exchangeCode.settlementPrice
			} else {
				if (sku.settle_flag) {
					settlementPrice = 0
				} else {
					settlementPrice = sku.settlement_price
				}
			}
			let account
			if (isBoss) {
				account = await dbHelper.getOne("t3ds-account", {
					userId: user._id
				})
			} else {
				account = await dbHelper.getOne("t3ds-account", {
					userId: store.uid
				})
			}
			account.total += settlementPrice;
			account.balance += settlementPrice;
			account.updateTime = Date.now();
			account.updateBy = user.username;
			console.log("更新老板账户");
			await dbHelper.update("t3ds-account", account, transaction);
			let accountLog = {
				accountId: account._id,
				userId: isBoss ? user._id : store.uid,
				total: account.total,
				income: settlementPrice,
				tradeType: 5,
				settled: true,
				settleTime: Date.now(),
				orderId: order._id,
				ticketCodeId: codeId,
				createTime: Date.now(),
				createBy: user.username
			}
			console.log("保存老板账户日志");
			await dbHelper.insert("t3ds-account-log", accountLog);

			let dbCmd = this.db.command
			console.log("结算佣金")
			var tradeType = [1, 2, 3, 4, 7, 8]
			// if (sku.settle_flag) {
			// 	tradeType = tradeType.concat([1, 3, 4, 7, 8])
			// }
			let accountLogs = await dbHelper.getList("t3ds-account-log", {
				settled: false,
				tradeType: dbCmd.in(tradeType),
				orderId: order._id
			});
			let countRes = await this.db.collection("t3ds-ticket-code").where({
				orderId: order._id,
				status: 0
			}).count();
			if (accountLogs.length) {
				for (var i = 0; i < accountLogs.length; i++) {
					var log = accountLogs[i];
					log = await dbHelper.getById("t3ds-account-log", log._id, transaction)
					if (log.settled) {
						continue
					}
					let brokrage = Math.round(log.income / orderItem.count)
					console.log("结算佣金", brokrage / 100);
					await transaction.collection("t3ds-account").doc(log.accountId).update({
						settle: dbCmd.inc(-brokrage),
						balance: dbCmd.inc(brokrage)
					})
					if (countRes.total === 1) {
						console.log("更新分销者账户日志为已结算");
						await transaction.collection("t3ds-account-log").doc(log._id).update({
							settled: true,
							settleTime: Date.now()
						});
					}
				}
			}
			if (countRes.total === 1) {
				console.log("更新订单状态为待评价")
				await transaction.collection("t3ds-order").doc(order._id).update({
					status: 4
				})
			}

			if (sku.receipts && sku.receipts.length) {
				let member = await dbHelper.getById("uni-id-users", order.user_id)
				let totalCount = await dbHelper.getCount("t3ds-receipts", {})

				for (var i = 0; i < sku.receipts.length; i++) {
					let item = sku.receipts[i]
					let deadline
					if (item.deadline.type === 'relative') {
						deadline = moment().tz("Asia/Shanghai").add(item.deadline.value, 'days').hour(
							23).minute(59).second(59).toDate().getTime()
					} else if (item.deadline.type === 'absolute') {
						deadline = moment.tz(item.deadline.value, "Asia/Shanghai").hour(23).minute(59)
							.second(59).toDate().getTime();
					} else {
						deadline = moment().tz("Asia/Shanghai").hour(23).minute(59).second(59).toDate()
							.getTime();
					}
					let t = {
						ticketId: codeId,
						storeId,
						storeName: store.name,
						orderId: order._id,
						uid: order.user_id,
						code: `11${member.id}${totalCount + i + 1}`,
						name: item.name,
						deadline: deadline,
						status: 0,
						goodsId: goods._id,
						skuId: sku._id,
						createTime: Date.now(),
						source: 'buy'
					}
					await transaction.collection("t3ds-receipts").add(t)
				}
			}

			code = Object.assign(code, data);
			await transaction.commit();
			return {
				code: 200,
				result: code
			}
		} catch (e) {
			console.log("核销遇到错误，codeId=", codeId, e);
			if (transaction) {
				await transaction.rollback();
			}
			return {
				code: 500,
				msg: e.message
			}
		}
	}

	async getTicketChargeoffRecords({
		storeId,
		startDate,
		endDate,
		pageNum = 1,
		pageSize = 20
	}) {
		let result = {
			total: 0,
			list: 0,
			totalIncome: 0
		}
		let dbCmd = this.db.command
		let $ = dbCmd.aggregate
		try {
			let user = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
			let isBoss = user.role.some(role => {
				return role === 'boss'
			})
			var where = []
			where.push({
				storeId: storeId
			})
			if (!isBoss) {
				where.push({
					employeeId: user.id + ''
				})
			}
			if (startDate && endDate) {
				where.push({
					chargeoffTime: dbCmd.gte(startDate).and(dbCmd.lte(endDate))
				})
			} else if (startDate) {
				where.push({
					chargeoffTime: dbCmd.gte(startDate)
				})
			} else if (endDate) {
				where.push({
					chargeoffTime: dbCmd.lte(endDate)
				})
			}
			where = dbCmd.and(where)
			let countRes = await this.db.collection("t3ds-ticket-code").where(where).count();
			if (!countRes.total) {
				return {
					code: 200,
					result
				}
			}
			let codeRes = await this.db.collection("t3ds-ticket-code").aggregate()
				.match(where)
				.sort({
					chargeoffTime: -1
				})
				.skip((pageNum - 1) * pageSize)
				.limit(pageSize)
				.lookup({
					from: "t3ds-order",
					localField: "orderId",
					foreignField: "_id",
					as: "order"
				})
				.unwind("$order")
				.lookup({
					from: "uni-id-users",
					localField: "order.user_id",
					foreignField: "_id",
					as: "member"
				})
				.unwind("$member")
				.project({
					_id: 1,
					goodsName: 1,
					goodsPrice: '$settlementPrice',
					employeeName: 1,
					chargeoffTime: 1,
					storeName: 1,
					source: 1,
					skuName: "$order.items.sku_name",
					nickname: "$order.user_nickname",
					mID: "$member.id"
				})
				.unwind("$skuName")
				.end();

			if (isBoss) {
				let query = {
					userId: this.ctx.auth.uid,
					tradeType: dbCmd.in([5, 9])
				}
				if (startDate && endDate) {
					query.createTime = dbCmd.gte(startDate).and(dbCmd.lte(endDate));
				} else if (startDate) {
					query.createTime = dbCmd.gte(startDate);
				} else if (endDate) {
					query.createTime = dbCmd.lte(endDate);
				}
				let totalIncomeRes = await this.db.collection("t3ds-account-log").aggregate()
					.match(query)
					.group({
						_id: null,
						total: $.sum('$income')
					})
					.end();
				if (totalIncomeRes.data.length) {
					result.totalFee = totalIncomeRes.data[0].total;
				}
				var totalIncome = 0
				if (totalIncomeRes.data.length) {
					totalIncome = totalIncomeRes.data[0].total
				}
				result.totalIncome = totalIncome
			}
			result.total = countRes.total
			result.list = codeRes.data
			return {
				code: 200,
				result
			}
		} catch (e) {
			return {
				code: 500,
				msg: e.message
			}
		}
	}

	async genPayInfo(payType, orderId) {
		let transaction = await this.db.startTransaction()
		try {
			let order = await dbHelper.getById("t3ds-order", orderId, transaction);
			if (!order) {
				await transaction.commit()
				return {
					code: 500,
					msg: "订单不存在"
				}
			}
			if (order.status !== 1) {
				await transaction.commit()
				return {
					code: 500,
					msg: "订单状态不正确"
				}
			}
			if (!order.payment_fee) {
				await transaction.commit()
				return {
					code: 500,
					msg: "订单不需要支付"
				}
			}
			let user = await dbHelper.getById('uni-id-users', this.ctx.auth.uid)

			if (payType == "tt") {
				console.log(order)
				let provider = 'ttpay'
				let platform = 'mp-tt'
				await transaction.collection("t3ds-order").doc(orderId).update({
					pay_type: provider,
					platform
				})
				const res = await this.ttPayService(order);
				await transaction.commit()
				return {
					code: 200,
					result: res
				}
			} else {
				let provider = 'wxpay'
				let platform = 'mp-weixin'
				await transaction.collection("t3ds-order").doc(orderId).update({
					pay_type: provider,
					platform
				})

				let uniPayInstance = payUtil.getPayInstance(provider, platform);
				let notifyUrl =
					`${CLOUDURL}/payment-notify/${provider}_${platform}`;
				let openid = user.wx_openid['mp-weixin'];
				let tradeType = payUtil.getTradeType(provider, platform);

				// 获取支付信息
				let orderInfo = await uniPayInstance.getOrderInfo({
					openid, // App端支付时不需要openid，传入个undefined也没有影响
					outTradeNo: order._id,
					totalFee: Math.floor(order.payment_fee),
					body: "第三空间-优惠平台",
					notifyUrl,
					tradeType
				})

				await transaction.commit()
				return {
					code: 200,
					result: orderInfo
				}
			}
		} catch (e) {
			await transaction.rollback()
			return {
				code: 500,
				result: e.message
			}
		}
	}

	async checkRoomLocked(roomId, startTime, endTime) {
		const db = this.db
		const dbCmd = this.db.command

		try {
			let res = await dbHelper.getById("t3ds-store-room", roomId)
			let res1 = await dbHelper.getList("t3ds-store-room", {
				storeId: res.storeId,
				name_number: res.name_number
			})
			let physicalRoom = {
				gameroomId: '',
				tearoomId: ''
			}
			for (let item of res1) {
				switch (item.type) {
					case 'gameroom':
						physicalRoom.gameroomId = item._id
						break;
					case 'tearoom':
						physicalRoom.tearoomId = item._id
						break;
					default:
						break;
				}
			}
			console.log("physicalRoom: ", physicalRoom);

			// 剧本杀
			let motorcadeCount = await db.collection("t3ds-subscribe-motorcade").where({
				// 'status': dbCmd.gt(0).and(dbCmd.lt(5)),
				'status': dbCmd.in([1, 2, 3, 4, -2]),
				'roomId': physicalRoom.gameroomId,
				'startTime': dbCmd.lt(endTime),
				'endTime': dbCmd.gt(startTime)
			}).count()
			// 茶室
			let teaCount = await db.collection('t3ds-order').where({
				'status': dbCmd.eq(3),
				['items.' + 0 + '.room_id']: physicalRoom.tearoomId,
				['items.' + 0 + '.start_time']: dbCmd.lt(endTime),
				['items.' + 0 + '.end_time']: dbCmd.gt(startTime)
			}).count()
			console.log("是否锁房间: ", motorcadeCount.total > 0 || teaCount.total > 0, motorcadeCount.total,
				teaCount.total);
			return motorcadeCount.total > 0 || teaCount.total > 0
		} catch (e) {
			throw e
		}
	}

	/**
	 * 创建固定时间拼车订单
	 */
	async genThemeOrder({
		skuId,
		themeId,
		maleCount,
		femaleCount,
		useBalance,
		shareManId,
		startTime,
		endTime,
		storeId,
		allowGetOn, //当当前人数大于等于最低人数后，是否允许继续加人
		motorcadeId, // 车队id
	}) {
		const transaction = await this.db.startTransaction();
		try {
			let dbCmd = this.db.command
			let $ = dbCmd.aggregate
			let count = maleCount + femaleCount // 总人数
			let motorcade = {}
			//获取门店信息
			let store = await dbHelper.getById("t3ds-store", storeId, transaction)
			if (!store) {
				await transaction.commit()
				return {
					code: 500,
					msg: "没有查找到门店信息"
				}
			}
			let theme = await dbHelper.getById("t3ds-theme-config", themeId);
			if (!theme) {
				await transaction.commit()
				return {
					code: 500,
					msg: "没有查找到当前主题信息"
				}
			}
			//校验信息
			let member = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
			if (!member.mobile) {
				await transaction.commit()
				return {
					code: 500,
					msg: '请先绑定手机号'
				}
			}
			var account = await dbHelper.getOne("t3ds-account", {
				userId: member._id
			});
			account = await dbHelper.getById("t3ds-account", account._id, transaction)
			let sku = await dbHelper.getById("t3ds-mall-sku", skuId, transaction);
			if (!sku) {
				await transaction.commit()
				return {
					code: 500,
					msg: "规格不存在"
				}
			}
			if (!sku.is_on_motorcade) {
				await transaction.commit()
				return {
					code: 500,
					msg: "规格不能拼车"
				}
			}
			let goods = await dbHelper.getById("t3ds-mall-goods", sku.goods_id);
			if (!goods) {
				await transaction.commit()
				return {
					code: 500,
					msg: "商品不存在"
				}
			}
			if (motorcadeId) {
				//加入车队的情况下
				//校验车队是否能继续添加
				motorcade = await dbHelper.getById("t3ds-motorcade", motorcadeId, transaction)
				if (motorcade.status > 1 || motorcade.status < 0) {
					throw new Error("已发车或已取消，不能加入了")
				}
				if (motorcade.currentMaleCount + motorcade.currentFemaleCount === motorcade.maxPlayers) {
					throw new Error("人数达到了上限，不能加入了")
				}
				if (motorcade.status == 1 && motorcade.currentMaleCount + motorcade.currentFemaleCount <
					motorcade.minPlayers && !motorcade.allowGetOn) {
					throw new Error("发起者不允许继续加人了")
				}
				if (motorcade.allowGetOn) {
					if (count + motorcade.currentMaleCount + motorcade.currentFemaleCount > motorcade
						.maxPlayers) {
						throw new Error(
							`人数超限，最多能加${motorcade.maxPlayers - motorcade.currentMaleCount + motorcade.currentFemaleCount}人`
						)
					}
				} else {
					if (count + motorcade.currentMaleCount + motorcade.currentFemaleCount > motorcade
						.minPlayers) {
						throw new Error(
							`人数超限，最多能加${motorcade.minPlayers - motorcade.currentMaleCount + motorcade.currentFemaleCount}人`
						)
					}
				}
				startTime = motorcade.startTime
				endTime = motorcade.endTime
			} else {
				//创建车队，校验当前时间段能否创建车队
				let res = await this.db.collection("t3ds-motorcade").where({
						startTime: startTime,
						endTime: endTime,
						sku_id: skuId,
						theme_id: themeId
					})
					.field({
						_id: true
					})
					.get()
				if (res && res.data.length > 0) {
					throw new Error("该时间段已有车队")
				}
			}
			//获取用户已购买当前票券的数量
			let payCount = await this.service.order.getTicketCount({
				skuId: skuId
			})
			console.log("已购买数量", payCount)
			let order = {}
			let item = {
				store_id: store._id,
				store_name: store.name,
				goods_id: goods._id,
				goods_name: goods.name,
				goods_thumb: goods.thumb,
				sku_id: sku._id,
				sku_name: sku.name,
				sku_is_on_motorcade: sku.is_on_motorcade || false,
				themeId: themeId,
				price: sku.price,
				//count: count,
				maleCount: maleCount,
				femaleCount: femaleCount,
				startTime: startTime,
				endTime: endTime,
				discountsForVip: sku.discountsForVip || 0,
				settlement_price: sku.settlement_price,
				settle_flag: sku.settle_flag
			}
			let totalFee = 0
			let paymentFee, income, discountsForVip;
			if (count > payCount) {
				count = count - payCount
				item.count = count
				//余票不足需要创建商品订单，在订单支付成功后创建押金记录订单
				if (!goods.is_on_sale && !goods.is_sell_on_off) {
					await transaction.commit()
					return {
						code: 500,
						msg: "商品已下架"
					}
				}
				if (!sku.is_on_sale) {
					await transaction.commit()
					return {
						code: 500,
						msg: "商品已下架"
					}
				}
				if (sku.stock < count) {
					await transaction.commit()
					return {
						code: 500,
						msg: "库存不足"
					}
				}
				//如果是秒杀商品
				if (sku.is_on_seckill) {
					let tempSku = []
					tempSku.push(sku._id)
					this.service.goods.syncSeckillStatus(tempSku)
					if (sku.amountNow < count) {
						await transaction.commit()
						return {
							code: 500,
							msg: "当前秒杀剩余数量不足"
						}
					}
					if (Date.now() > sku.endNowDate) {
						await transaction.commit()
						return {
							code: 500,
							msg: "当前时间无法秒杀该商品"
						}
					}
				}
				if (goods.is_time_limited) {
					if (goods.sale_deadline < Date.now()) {
						await transaction.commit()
						return {
							code: 500,
							msg: "该商品已结束抢购！"
						}
					}
				}
				if (sku.buy_limit_count) {
					// 处理限购
					let res = await this.db.collection("t3ds-order").aggregate()
						.match({
							user_id: member._id,
							'items.sku_id': sku._id,
							status: dbCmd.gte(1)
						})
						.unwind("$items")
						.group({
							_id: null,
							count: $.sum("$items.count")
						})
						.end()
					var buyCount = 0
					if (res.data.length) {
						buyCount = res.data[0].count
					}
					if (buyCount >= sku.buy_limit_count) {
						await transaction.commit()
						return {
							code: 500,
							msg: "限购商品已达限购数量"
						}
					}
					if (buyCount + count > sku.buy_limit_count) {
						await transaction.commit()
						return {
							code: 500,
							msg: `此商品每人限购${sku.buy_limit_count}份，只能再购买${sku.buy_limit_count - buyCount}份`
						}
					}
				}

				sku.stock -= count;
				if (sku.is_on_seckill && sku.seckill_status == 1) {
					sku.amountNow -= count;
				}
				if (!sku.sellCount) {
					sku.sellCount = 0;
				}
				sku.sellCount += count;
				await dbHelper.update("t3ds-mall-sku", sku, transaction);
				await dbHelper.update("t3ds-mall-goods", {
					_id: sku.goods_id,
					totalStock: dbCmd.inc(-count),
					totalSellCount: dbCmd.inc(count)
				}, transaction)
				totalFee = sku.price * count
				let isSuperVip = member.vipInfo && member.vipInfo.storeVipCardInfo &&
					member.vipInfo.storeVipCardInfo.expirationTime >= Date.now() &&
					member.vipInfo.storeVipCardInfo.settlementWay === 'time'
				if (isSuperVip && sku.discountsForVip && sku.discountsForVip > 0) {
					discountsForVip = sku.discountsForVip * count
					// totalFee = sku.price * count - discountsForVip
					// if (totalFee < 0) {
					// 	totalFee = 0
					// }
				} else {
					discountsForVip = 0
					// totalFee = sku.price * count
				}
				//实际支付金额需要包含押金
				// paymentFee = paymentFee + theme.cashPledge
				if (useBalance && account && account.balance) {
					if ((totalFee + theme.cashPledge) > account.balance) {
						paymentFee = totalFee + theme.cashPledge - discountsForVip - account.balance;
						account.frozen += account.balance;
						account.balance = 0;
						income = account.balance;
					} else {
						paymentFee = 0;
						account.balance -= totalFee + theme.cashPledge;
						account.frozen += totalFee + theme.cashPledge;
						income = totalFee + theme.cashPledge;
					}
					console.log("余额支付更新账户", account);
					await dbHelper.update("t3ds-account", account, transaction);
				} else {
					paymentFee = totalFee + theme.cashPledge;
				}
				//生成商品订单
				order = {
					total_fee: Math.round(totalFee),
					discounts_for_vip: discountsForVip || 0,
					payment_fee: Math.round(paymentFee),
					user_id: member._id,
					user_nickname: member.nickname,
					user_phone: member.mobile,
					platform: "mp-weixin",
					status: 1,
					items: [item],
					use_balance: useBalance ? true : false,
					create_time: Date.now(),
					create_by: member.nickname,
					type: 'goods',
					channel: goods.channel || 'self',
					allowGetOn: allowGetOn,
					detain_fee: Math.round(theme.cashPledge),
					detain_status: 1
				}
				if (motorcadeId) {
					order.motorcadeId = motorcadeId
				}
				//分享ID
				if (shareManId) {
					let shareMan = await this.service.member.setupShareManId({
						memberId: this.ctx.auth.uid,
						shareManId: parseInt(shareManId)
					})
					if (shareMan) {
						order.shareManId = shareMan.id;
					}
				}
				await dbHelper.insert("t3ds-order", order, transaction);
				if (income) {
					await dbHelper.insert("t3ds-account-log", {
						accountId: account._id,
						total: account.total,
						income: income,
						tradeType: -1,
						orderId: order._id,
						settled: true,
						createTime: Date.now(),
						createBy: member.nickname
					}, transaction);
				}
			} else {
				//只需要生成押金订单,调用生成押金的接口
				console.log("生成押金订单的接口")
				item.count = 0
				totalFee = theme.cashPledge
				if (useBalance && account && account.balance) {
					if (totalFee > account.balance) {
						paymentFee = totalFee - account.balance;
						account.frozen += account.balance;
						account.balance = 0;
						income = account.balance;
					} else {
						paymentFee = 0;
						account.balance -= totalFee;
						account.frozen += totalFee;
						income = totalFee;
					}
					console.log("余额支付更新账户", account);
					await dbHelper.update("t3ds-account", account, transaction);
				} else {
					paymentFee = totalFee;
				}
				order = {
					total_fee: Math.round(totalFee),
					payment_fee: Math.round(paymentFee),
					user_id: member._id,
					user_nickname: member.nickname,
					user_phone: member.mobile,
					platform: "mp-weixin",
					status: 1,
					items: [item],
					use_balance: useBalance ? true : false,
					create_time: Date.now(),
					create_by: member.nickname,
					type: 'detain',
					allowGetOn: allowGetOn
				}
				if (motorcadeId) {
					order.motorcadeId = motorcadeId
				}
				await dbHelper.insert("t3ds-order", order, transaction);
				if (income) {
					await dbHelper.insert("t3ds-account-log", {
						accountId: account._id,
						total: account.total,
						income: income,
						tradeType: -1,
						orderId: order._id,
						settled: true,
						createTime: Date.now(),
						createBy: member.nickname
					}, transaction);
				}
			}
			// //判断是否已支付商品订单
			// let goodOrder = await this.db.collection("t3ds-order").aggregate()
			// 	.match({
			// 		user_id: member._id,
			// 		'items.sku_id': sku._id,
			// 		status: dbCmd.eq(2)
			// 	})
			// 	.end()
			// let order = {}
			// if(goodOrder.data.length < 1) {
			// 	//该用户未支付商品订单
			// 	//生成商品订单和押金订单
			// }
			// if(theme.sku_id == sku._id) {
			// 	//生成押金订单
			// 	let order2 = {
			// 		total_fee: Math.round(theme.cashPledge),
			// 		payment_fee: Math.round(theme.cashPledge),
			// 		user_id: member._id,
			// 		user_nickname: member.nickname,
			// 		user_phone: member.mobile,
			// 		platform: "mp-weixin",
			// 		status: 1,
			// 		items: [item],
			// 		use_balance: false,
			// 		create_time: Date.now(),
			// 		create_by: member.nickname,
			// 		type: 'detain',
			// 		allowGetOn: allowGetOn
			// 	}
			// 	if(motorcadeId) {
			// 		order2.motorcadeId = motorcadeId
			// 	}
			// 	await dbHelper.insert("t3ds-order", order2, transaction);
			// }
			await transaction.commit();
			console.log("创建订单成功, 提交事务");
			return order
		} catch (e) {
			console.error("创建订单遇到错误, 事务回滚", e);
			throw e
		}
	}

	/**
	 * 创建预约剧本杀订单 
	 */
	async genSubscribeScriptOrder({
		orderType,
		scriptId,
		maleCount,
		femaleCount,
		startTime,
		endTime,
		storeId,
		roomId,
		useBalance = false,
		allowGetOn, //当当前人数大于等于最低人数后，是否允许继续加人
		motorcadeId, // 车队id
		couponId, //优惠券id
		// buyCardId, //会员卡/折扣卡id
		shareManId,
		currentOrderId
	}) {
		const transaction = await this.db.startTransaction();

		const dbCmd = this.db.command
		const $ = dbCmd.aggregate

		try {
			let coupon = await verifyCoupon(transaction, this.ctx.auth.uid, couponId, startTime, orderType,
				storeId, motorcadeId || '')

			let count = maleCount + femaleCount // 总人数

			let motorcade = {}
			let script = {}
			let store = {}
			let room = {}

			store = await dbHelper.getById("t3ds-store", storeId, transaction)

			if (orderType === 'renewal') {
				motorcade = await dbHelper.getById("t3ds-subscribe-motorcade", motorcadeId, transaction)
				if (motorcade.status > 4 || motorcade.status === -1) {
					throw new Error("已结束或已取消，不能续时了")
				}

				if (motorcade.roomId) {
					room = await dbHelper.getById("t3ds-store-room", motorcade.roomId, transaction)
					let roomLocked = await this.checkRoomLocked(roomId, startTime, endTime)
					if (roomLocked) {
						throw new Error("该时间段的房间已被预定，请选择其他时间段续时")
					}
				}

				script = await dbHelper.getById("t3ds-script", motorcade.scriptId)
			} else {
				if (motorcadeId) {
					motorcade = await dbHelper.getById("t3ds-subscribe-motorcade", motorcadeId, transaction)
					if (motorcade.status > 1 || motorcade.status < 0) {
						throw new Error("已发车或已取消，不能加入了")
					}
					if (motorcade.currentMaleCount + motorcade.currentFemaleCount === motorcade.maxPlayers) {
						throw new Error("人数达到了上限，不能加入了")
					}
					if (motorcade.status == 1 && motorcade.currentMaleCount + motorcade.currentFemaleCount <
						motorcade.minPlayers && !motorcade.allowGetOn) {
						throw new Error("发起者不允许继续加人了")
					}
					if (motorcade.allowGetOn) {
						if (count + motorcade.currentMaleCount + motorcade.currentFemaleCount > motorcade
							.maxPlayers) {
							throw new Error(
								`人数超限，最多能加${motorcade.maxPlayers - motorcade.currentMaleCount + motorcade.currentFemaleCount}人`
							)
						}
					} else {
						if (count + motorcade.currentMaleCount + motorcade.currentFemaleCount > motorcade
							.minPlayers) {
							throw new Error(
								`人数超限，最多能加${motorcade.minPlayers - motorcade.currentMaleCount + motorcade.currentFemaleCount}人`
							)
						}
					}
					script = await dbHelper.getById("t3ds-script", motorcade.scriptId)
					if (motorcade.roomId) {
						room = await dbHelper.getById("t3ds-store-room", motorcade.roomId, transaction)
						if (!room.enabled) {
							throw new Error("房间不可用")
						}
						let roomLocked = await this.checkRoomLocked(roomId, startTime, endTime)
						if (roomLocked) {
							throw new Error("该时间段的房间已被预定，请选择其他时间段")
						}
					}
					startTime = motorcade.startTime
					endTime = motorcade.endTime
				} else {
					script = await dbHelper.getById("t3ds-script", scriptId, transaction)
					if (!script) {
						throw new Error("剧本不存在")
					}
					if (!script.isOnSell) {
						throw new Error("剧本已下架")
					}
					if (!script.isPurchased && startTime < Date.now() + 1000 * 60 * 60 * 24 * 4) {
						throw new Error("该剧本需要提前4天预约")
					}
					if (roomId) {
						room = await dbHelper.getById("t3ds-store-room", roomId, transaction)
						if (!room) {
							throw new Error("房间不存在")
						}
						if (!room.enabled) {
							throw new Error("房间不可用")
						}
						let roomLocked = await this.checkRoomLocked(roomId, startTime, endTime)
						if (roomLocked) {
							throw new Error("该时间段的房间已被预定，请选择其他时间段")
						}
						let count = await dbHelper.getCount("t3ds-subscribe-motorcade", dbCmd.and([{
							status: dbCmd.gte(0).and(dbCmd.lt(5)),
							scriptId,
							roomId,
							initiator: this.ctx.auth.uid
						}, dbCmd.or([{
							startTime: dbCmd.lte(startTime),
							endTime: dbCmd.gte(startTime)
						}, {
							startTime: dbCmd.lte(endTime),
							endTime: dbCmd.gte(endTime)
						}])]))
						if (count) {
							throw new Error("您不能再次预定同时段的房间了")
						}
					}
				}
			}

			let pricePerHour = script.price / script.playTime
			let time = (endTime - startTime) / oneHourInMills

			// 更新账户余额
			let {
				discountsForVip,
				totalFee,
				paymentFee,
				discount_fee,
				member,
				use_balance_fee,
				income,
				account
			} = await updataAccountBalance(transaction, this.ctx, time, pricePerHour, room, store, count,
				coupon, useBalance)

			// 生成预约订单 或 续时订单
			let item = {
				store_id: store._id,
				store_name: store.name,
				unifyPrice: store.unifyPrice || 0,
				script_id: script._id,
				script_name: script.name,
				script_price: script.price,
				script_cover: script.cover,
				start_time: startTime,
				end_time: endTime,
				count,
				maleCount,
				femaleCount,
				discountsForVip
			}
			if (roomId) {
				item.room_id = room._id
				item.room_name = room.name
				item.room_capacity = room.capacity
				item.room_price = room.price
				item.settlement_price = room.settlementPrice
			}
			let order = {
				total_fee: Math.round(totalFee),
				discounts_for_vip: discountsForVip || 0,
				payment_fee: Math.round(paymentFee),
				user_id: member._id,
				user_nickname: member.nickname || '微信用户',
				user_phone: member.mobile,
				platform: "mp-weixin",
				status: 1,
				items: [item],
				motorcadeId,
				allowGetOn,
				use_balance: useBalance ? true : false,
				use_balance_fee: use_balance_fee || 0,
				create_time: Date.now(),
				create_by: member.nickname || '微信用户'
			}
			if (orderType === 'renewal') {
				order.type = 'renewal'
			} else {
				order.type = 'subscribe'
			}
			if (coupon) {
				order.couponId = couponId
				order.discount_fee = discount_fee
			}
			console.log("shareManId: ", shareManId);
			if (shareManId && parseInt(shareManId) != member.id) {
				order.shareManId = parseInt(shareManId);
			}
			await dbHelper.insert("t3ds-order", order, transaction);

			if (income) {
				await dbHelper.insert("t3ds-account-log", {
					accountId: account._id,
					total: account.total,
					income: income,
					tradeType: -1,
					orderId: order._id,
					settled: true,
					createTime: Date.now(),
					createBy: member.id + ''
				}, transaction);
			}

			if (orderType === 'renewal') {
				let renewalOrdersId = [{
					renewalOrderId: order._id,
					subscribeOrderId: currentOrderId
				}]
				// 车队其他成员同时生成未支付的续时订单
				let res = await this.db.collection('t3ds-order').aggregate()
					.match({
						_id: dbCmd.in(motorcade.orderIds)
					})
					.match({
						_id: dbCmd.neq(currentOrderId)
					})
					.lookup({
						from: 'uni-id-users',
						localField: 'user_id',
						foreignField: '_id',
						as: 'member'
					})
					.project({
						items: 1,
						member: 1
					})
					.end()
				// console.log("res: ",res);
				for (let i = 0; i < res.data.length; i++) {
					let item = {
						store_id: store._id,
						store_name: store.name,
						unifyPrice: store.unifyPrice || 0,
						script_id: script._id,
						script_name: script.name,
						script_price: script.price,
						start_time: startTime,
						end_time: endTime,
						count,
						maleCount: res.data[i].items[0].maleCount,
						femaleCount: res.data[i].items[0].femaleCount
					}

					if (roomId) {
						item.room_id = room._id
						item.room_name = room.name
						item.room_capacity = room.capacity
						item.room_price = room.price
						item.settlement_price = room.settlementPrice
					}

					let otherOrder = {
						total_fee: Math.round((pricePerHour + (room.price || store.unifyPrice || 0)) *
							time * (res.data[i].items[0].maleCount + res.data[i].items[0].femaleCount)),
						// discounts_for_vip: discountsForVip || 0,
						// payment_fee: Math.round(paymentFee),
						user_id: res.data[i].member[0]._id,
						user_nickname: res.data[i].member[0].nickname || '微信用户',
						user_phone: res.data[i].member[0].mobile,
						platform: "mp-weixin",
						status: 1,
						items: [item],
						motorcadeId,
						allowGetOn,
						// use_balance: useBalance ? true : false,
						// use_balance_fee: use_balance_fee || 0,
						create_time: Date.now(),
						create_by: '系统',
						type: 'renewal'
					}
					// console.log("order: ",order);
					await dbHelper.insert("t3ds-order", otherOrder, transaction);
					renewalOrdersId.push({
						renewalOrderId: otherOrder._id,
						subscribeOrderId: res.data[i]._id
					})
				}

				// console.log("motorcade: ",motorcade);
				let notPaidInFull = true
				if (!res.data.length) { // 车队没有其他成员
					notPaidInFull = false
					motorcade.endTime = order.items[0].end_time
				}
				// motorcade.renewalOrders = [
				//   {
				//     没有都支付,
				//     续时多久,
				//     续时结束时间,
				//     所有成员订单id: [
				//       {
				//         续时订单id,
				//         相关联的预约订单id
				//       }
				//     ]
				//   }
				// ]
				if (motorcade.renewalOrders && motorcade.renewalOrders.length > 0) {
					motorcade.renewalOrders.unshift({
						notPaidInFull,
						renewalDuration: order.items[0].end_time - order.items[0].start_time,
						renewalEndTime: order.items[0].end_time,
						renewalOrdersId: renewalOrdersId
					})
				} else {
					motorcade.renewalOrders = [{
						notPaidInFull,
						renewalDuration: order.items[0].end_time - order.items[0].start_time,
						renewalEndTime: order.items[0].end_time,
						renewalOrdersId: renewalOrdersId
					}]
				}
				await dbHelper.update("t3ds-subscribe-motorcade", {
					_id: motorcade._id,
					endTime: motorcade.endTime,
					renewalOrders: motorcade.renewalOrders
				}, transaction);
			}

			await transaction.commit();

			try {
				if (!order.payment_fee) {
					await orderHelper.handleOrderPaid(order._id, Date.now())
					order = await dbHelper.getById("t3ds-order", order._id)
				}
			} catch (e) {}

			console.log("创建订单成功, 提交事务");
			return order
		} catch (e) {
			console.error("创建订单遇到错误, 事务回滚", e);
			await transaction.rollback();
			throw e
		}
	}

	// 计算头条请求签名sign
	ttPayMd5(params) {
		var skip_arr = ["thirdparty_id", "app_id", "sign"];
		var paramArray = new Array();
		for (var k in params) {
			if (skip_arr.indexOf(k) != -1) {
				continue;
			}
			if (params[k] == "") {
				continue;
			}
			paramArray.push(params[k]);
		}
		paramArray.push("9yTlZfGgRntRbkgU8Kr4glsETNOHfjbKZKzKDlie");
		paramArray.sort();
		var signStr = paramArray.join("&");
		return md5(signStr);
	}




	// 头条支付
	async ttPayService(paramsPay) {
		console.log(paramsPay)
		let params = {}
		if (paramsPay.type == "subscribe") {
			params = {
				"app_id": "ttc46fb2d25b563c6601",
				"out_order_no": paramsPay._id,
				"total_amount": paramsPay.payment_fee,
				// "total_amount": 1,
				"subject": paramsPay.items[0].script_name,
				"body": paramsPay.items[0].room_name,
				"valid_time": 900,
			}
		}

		if (paramsPay.type == "openVip") {
			params = {
				"app_id": "ttc46fb2d25b563c6601",
				"out_order_no": paramsPay._id,
				"total_amount": paramsPay.items[0].price,
				"subject": paramsPay.items[0].name,
				"body": paramsPay.items[0].rights,
				"valid_time": 900,
			}
		}
		if (paramsPay.type == "goods") {
			params = {
				"app_id": "ttc46fb2d25b563c6601",
				"out_order_no": paramsPay._id,
				"total_amount": paramsPay.items[0].price,
				// "total_amount": 1,
				"subject": paramsPay.items[0].sku_name,
				"body": paramsPay.items[0].goods_name,
				"valid_time": 900,
			}
		}
		if (paramsPay.type == "recharge") {
			params = {
				"app_id": "ttc46fb2d25b563c6601",
				"out_order_no": paramsPay._id,
				"total_amount": paramsPay.payment_fee,
				// "total_amount": 1,
				"subject": "押金",
				"body": "押金",
				"valid_time": 900,
			}
		}


		console.log(params)
		params.sign = this.ttPayMd5(params)
		let resp = await uniCloud.httpclient.request(
			"https://developer.toutiao.com/api/apps/ecpay/v1/create_order", {
				method: 'POST',
				data: params,
				contentType: 'json', // 指定以application/json发送data内的数据
				dataType: 'json' // 指定返回值为json格式，自动进行parse
			})
		return resp
	}

	// 头条支付
	async ttPayService2(paramsPay) {
		let params = {
			"app_id": "ttc46fb2d25b563c6601",
			"out_order_no": paramsPay._id,
			"total_amount": paramsPay.items[0].price,
			// "total_amount": 1,
			"subject": paramsPay.items[0].name,
			"body": paramsPay.items[0].rights,
			"valid_time": 900,
		}

		console.log(params)
		params.sign = this.ttPayMd5(params)
		let resp = await uniCloud.httpclient.request(
			"https://developer.toutiao.com/api/apps/ecpay/v1/create_order", {
				method: 'POST',
				data: params,
				contentType: 'json', // 指定以application/json发送data内的数据
				dataType: 'json' // 指定返回值为json格式，自动进行parse
			})
		return resp
	}







	// 退款方法
	async ttPayRefundService(out_order_no, out_refund_no, reason, refund_amount) {
		let params = {
			"app_id": "ttc46fb2d25b563c6601",
			"out_order_no": out_order_no,
			"out_refund_no": out_refund_no,
			"reason": reason,
			"refund_amount": refund_amount,
		}
		params.sign = this.ttPayMd5(params)
		let resp = await uniCloud.httpclient.request(
			"https://developer.toutiao.com/api/apps/ecpay/v1/create_refund", {
				method: 'POST',
				data: params,
				contentType: 'json', // 指定以application/json发送data内的数据
				dataType: 'json' // 指定返回值为json格式，自动进行parse
			})
		return resp
	}









	async genGoodsOrder(skuId, count, useBalance, shareManId, type) {
		const transaction = await this.db.startTransaction();
		try {
			let dbCmd = this.db.command
			let $ = dbCmd.aggregate
			let member = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
			if (type == "wx") {
				if (!member.mobile) {
					await transaction.commit()
					return {
						code: 500,
						msg: '请先绑定手机号'
					}
				}
			}
			var account = await dbHelper.getOne("t3ds-account", {
				userId: member._id
			});
			account = await dbHelper.getById("t3ds-account", account._id, transaction)
			let sku = await dbHelper.getById("t3ds-mall-sku", skuId, transaction);
			if (!sku) {
				await transaction.commit()
				return {
					code: 500,
					msg: "规格不存在"
				}
			}
			if (sku.stock < count) {
				await transaction.commit()
				return {
					code: 500,
					msg: "库存不足"
				}
			}
			let goods = await dbHelper.getById("t3ds-mall-goods", sku.goods_id);
			if (goods.is_time_limited) {
				if (goods.sale_deadline < Date.now()) {
					await transaction.commit()
					return {
						code: 500,
						msg: "该商品已结束抢购！"
					}
				}
			}

			if (sku.buy_limit_count) {
				// 处理限购
				let res = await this.db.collection("t3ds-order").aggregate()
					.match({
						user_id: member._id,
						'items.sku_id': sku._id,
						status: dbCmd.gte(1)
					})
					.unwind("$items")
					.group({
						_id: null,
						count: $.sum("$items.count")
					})
					.end()
				var buyCount = 0
				if (res.data.length) {
					buyCount = res.data[0].count
				}
				if (buyCount >= sku.buy_limit_count) {
					await transaction.commit()
					return {
						code: 500,
						msg: "限购商品已达限购数量"
					}
				}
				if (buyCount + count > sku.buy_limit_count) {
					await transaction.commit()
					return {
						code: 500,
						msg: `此商品每人限购${sku.buy_limit_count}份，只能再购买${sku.buy_limit_count - buyCount}份`
					}
				}
			}
			if (goods.type === 'vipCard' && member.vipInfo) {
				let vipCard = await dbHelper.getById("t3ds-vip-card", sku.vip_card_id)
				// console.log('vipCard', vipCard, member.vipInfo)
				if (member.vipInfo.storeVipCardInfo && vipCard.type === 'store') {
					if (member.vipInfo.storeVipCardInfo.expirationTime > Date.now() &&
						vipCard.level < member.vipInfo.storeVipCardInfo.level) {
						return {
							code: 500,
							msg: '不能购买比当前卡等级低的卡'
						}
					}
					if (member.vipInfo.storeVipCardInfo.expirationTime > Date.now() &&
						vipCard.settlementWay !== member.vipInfo.storeVipCardInfo.settlementWay) {
						return {
							code: 500,
							msg: '不能购买与当前卡种类不相同的卡'
						}
					}
				}
			}

			sku.stock -= count;
			if (!sku.sellCount) {
				sku.sellCount = 0;
			}
			sku.sellCount += count;
			await dbHelper.update("t3ds-mall-sku", sku, transaction);
			await dbHelper.update("t3ds-mall-goods", {
				_id: sku.goods_id,
				totalStock: dbCmd.inc(-count),
				totalSellCount: dbCmd.inc(count)
			}, transaction)
			let totalFee = sku.price * count
			let paymentFee, income, discountsForVip;
			let isSuperVip = member.vipInfo && member.vipInfo.storeVipCardInfo &&
				member.vipInfo.storeVipCardInfo.expirationTime >= Date.now() &&
				member.vipInfo.storeVipCardInfo.settlementWay === 'time'
			if (isSuperVip && sku.discountsForVip && sku.discountsForVip > 0) {
				discountsForVip = sku.discountsForVip * count
				// totalFee = sku.price * count - discountsForVip
				// if (totalFee < 0) {
				// 	totalFee = 0
				// }
			} else {
				discountsForVip = 0
				// totalFee = sku.price * count
			}
			if (useBalance && account && account.balance) {
				if (totalFee > account.balance) {
					paymentFee = totalFee - discountsForVip - account.balance;
					account.frozen += account.balance;
					account.balance = 0;
					income = account.balance;
				} else {
					paymentFee = 0;
					account.balance -= totalFee;
					account.frozen += totalFee;
					income = totalFee;
				}
				console.log("余额支付更新账户", account);
				await dbHelper.update("t3ds-account", account, transaction);
			} else {
				paymentFee = totalFee;
			}

			let item = {
				goods_id: goods._id,
				goods_name: goods.name,
				goods_thumb: goods.thumb,
				sku_id: sku._id,
				sku_name: sku.name,
				sku_is_on_motorcade: sku.is_on_motorcade || false,
				price: sku.price,
				count: count,
				discountsForVip: sku.discountsForVip || 0,
				settlement_price: sku.settlement_price,
				settle_flag: sku.settle_flag
			}
			let order = {
				total_fee: Math.round(totalFee),
				discounts_for_vip: discountsForVip || 0,
				payment_fee: Math.round(paymentFee),
				user_id: member._id,
				user_nickname: member.nickname,
				user_phone: member.mobile,
				// 不同平台
				platform: type == "wx" ? "mp-weixin" : "mp-toutiao",
				status: 1,
				items: [item],
				use_balance: useBalance ? true : false,
				create_time: Date.now(),
				create_by: member.nickname,
				type: 'goods',
				channel: goods.channel || 'self'
			}
			if (shareManId) {
				let shareMan = await this.service.member.setupShareManId({
					memberId: this.ctx.auth.uid,
					shareManId: parseInt(shareManId)
				})
				order.shareManId = shareMan.id;
			}
			await dbHelper.insert("t3ds-order", order, transaction);

			if (income) {
				await dbHelper.insert("t3ds-account-log", {
					accountId: account._id,
					total: account.total,
					income: income,
					tradeType: -1,
					orderId: order._id,
					settled: true,
					createTime: Date.now(),
					createBy: member.nickname,
					userId: member._id,
					settle: account.settle,
					balance: account.balance,
					frozen: account.frozen,
				}, transaction);
			}

			await transaction.commit();
			console.log("创建订单成功, 提交事务");
			return {
				code: 200,
				result: order
			}
		} catch (e) {
			console.error("创建订单遇到错误, 事务回滚", e);
			await transaction.rollback();
			return {
				code: 500,
				msg: e.message
			}
		}
	}

	//创建秒杀商品订单（未完善）
	async genSeckillGoodsOrder(skuId, count, useBalance, shareManId) {
		const transaction = await this.db.startTransaction();
		try {
			let dbCmd = this.db.command
			let $ = dbCmd.aggregate
			let member = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
			if (!member.mobile) {
				await transaction.commit()
				return {
					code: 500,
					msg: '请先绑定手机号'
				}
			}
			var account = await dbHelper.getOne("t3ds-account", {
				userId: member._id
			});
			account = await dbHelper.getById("t3ds-account", account._id, transaction)
			let sku = await dbHelper.getById("t3ds-mall-sku", skuId, transaction);
			if (!sku) {
				await transaction.commit()
				return {
					code: 500,
					msg: "规格不存在"
				}
			}
			if (sku.stock < count) {
				await transaction.commit()
				return {
					code: 500,
					msg: "库存不足"
				}
			}
			let goods = await dbHelper.getById("t3ds-mall-goods", sku.goods_id);
			if (goods.is_time_limited) {
				if (goods.sale_deadline < Date.now()) {
					await transaction.commit()
					return {
						code: 500,
						msg: "该商品已结束抢购！"
					}
				}
			}

			if (sku.buy_limit_count) {
				// 处理限购
				let res = await this.db.collection("t3ds-order").aggregate()
					.match({
						user_id: member._id,
						'items.sku_id': sku._id,
						status: dbCmd.gte(1)
					})
					.unwind("$items")
					.group({
						_id: null,
						count: $.sum("$items.count")
					})
					.end()
				var buyCount = 0
				if (res.data.length) {
					buyCount = res.data[0].count
				}
				if (buyCount >= sku.buy_limit_count) {
					await transaction.commit()
					return {
						code: 500,
						msg: "限购商品已达限购数量"
					}
				}
				if (buyCount + count > sku.buy_limit_count) {
					await transaction.commit()
					return {
						code: 500,
						msg: `此商品每人限购${sku.buy_limit_count}份，只能再购买${sku.buy_limit_count - buyCount}份`
					}
				}
			}
			if (goods.type === 'vipCard' && member.vipInfo) {
				let vipCard = await dbHelper.getById("t3ds-vip-card", sku.vip_card_id)
				// console.log('vipCard', vipCard, member.vipInfo)
				if (member.vipInfo.storeVipCardInfo && vipCard.type === 'store') {
					if (member.vipInfo.storeVipCardInfo.expirationTime > Date.now() &&
						vipCard.level < member.vipInfo.storeVipCardInfo.level) {
						return {
							code: 500,
							msg: '不能购买比当前卡等级低的卡'
						}
					}
					if (member.vipInfo.storeVipCardInfo.expirationTime > Date.now() &&
						vipCard.settlementWay !== member.vipInfo.storeVipCardInfo.settlementWay) {
						return {
							code: 500,
							msg: '不能购买与当前卡种类不相同的卡'
						}
					}
				}
			}

			sku.stock -= count;
			if (!sku.sellCount) {
				sku.sellCount = 0;
			}
			sku.sellCount += count;
			await dbHelper.update("t3ds-mall-sku", sku, transaction);
			await dbHelper.update("t3ds-mall-goods", {
				_id: sku.goods_id,
				totalStock: dbCmd.inc(-count),
				totalSellCount: dbCmd.inc(count)
			}, transaction)
			let totalFee = sku.price * count
			let paymentFee, income, discountsForVip;
			let isSuperVip = member.vipInfo && member.vipInfo.storeVipCardInfo &&
				member.vipInfo.storeVipCardInfo.expirationTime >= Date.now() &&
				member.vipInfo.storeVipCardInfo.settlementWay === 'time'
			if (isSuperVip && sku.discountsForVip && sku.discountsForVip > 0) {
				discountsForVip = sku.discountsForVip * count
				// totalFee = sku.price * count - discountsForVip
				// if (totalFee < 0) {
				// 	totalFee = 0
				// }
			} else {
				discountsForVip = 0
				// totalFee = sku.price * count
			}
			if (useBalance && account && account.balance) {
				if (totalFee > account.balance) {
					paymentFee = totalFee - discountsForVip - account.balance;
					account.frozen += account.balance;
					account.balance = 0;
					income = account.balance;
				} else {
					paymentFee = 0;
					account.balance -= totalFee;
					account.frozen += totalFee;
					income = totalFee;
				}
				console.log("余额支付更新账户", account);
				await dbHelper.update("t3ds-account", account, transaction);
			} else {
				paymentFee = totalFee;
			}

			let item = {
				goods_id: goods._id,
				goods_name: goods.name,
				goods_thumb: goods.thumb,
				sku_id: sku._id,
				sku_name: sku.name,
				price: sku.price,
				count: count,
				discountsForVip: sku.discountsForVip || 0,
				settlement_price: sku.settlement_price
			}
			let order = {
				total_fee: Math.round(totalFee),
				discounts_for_vip: discountsForVip || 0,
				payment_fee: Math.round(paymentFee),
				user_id: member._id,
				user_nickname: member.nickname,
				user_phone: member.mobile,
				platform: "mp-weixin",
				status: 1,
				items: [item],
				use_balance: useBalance ? true : false,
				create_time: Date.now(),
				create_by: member.nickname,
				type: 'goods',
				channel: goods.channel || 'self'
			}
			if (shareManId) {
				let shareMan = await this.service.member.setupShareManId({
					memberId: this.ctx.auth.uid,
					shareManId: parseInt(shareManId)
				})
				order.shareManId = shareMan.id;
			}
			await dbHelper.insert("t3ds-order", order, transaction);

			if (income) {
				await dbHelper.insert("t3ds-account-log", {
					accountId: account._id,
					total: account.total,
					income: income,
					tradeType: -1,
					orderId: order._id,
					settled: true,
					createTime: Date.now(),
					createBy: member.nickname
				}, transaction);
			}

			await transaction.commit();
			console.log("创建订单成功, 提交事务");
			return {
				code: 200,
				result: order
			}
		} catch (e) {
			console.error("创建订单遇到错误, 事务回滚", e);
			await transaction.rollback();
			return {
				code: 500,
				msg: e.message
			}
		}
	}

	//创建礼包订单
	async genPackageOrder(packageInfo) {
		let transaction = await this.db.startTransaction()
		let userInfo = await dbHelper.getById("uni-id-users", this.ctx.auth.uid, transaction)
		try {
			let order = {
				total_fee: packageInfo.packageTopupAmount,
				payment_fee: packageInfo.packageTopupAmount,
				user_id: userInfo._id,
				user_nickname: userInfo.nickname || userInfo.username,
				platform: "mp-weixin",
				items: [{
					count: 1,
					goods_id: packageInfo._id
				}],
				status: 1,
				create_time: Date.now(),
				use_balance: false,
				create_by: userInfo.nickname,
				type: 'package'
			}
			await dbHelper.insert("t3ds-order", order, transaction)
			await transaction.commit()
			return {
				code: 200,
				result: order
			}
		} catch (e) {
			await transaction.rollback()
			console.error(e)
			return {
				code: 500,
				msg: e.message
			}
		}
	}

	async genOpenVipOrder(vipCard, payType) {
		let transaction = await this.db.startTransaction()
		try {
			let userInfo = await dbHelper.getById("uni-id-users", this.ctx.auth.uid, transaction)

			if (payType != "tt") {
				if (!userInfo.mobile) {
					await transaction.commit()
					return {
						code: 500,
						msg: '请先绑定手机号'
					}
				}
			}
			console.log("111111")
			if (vipCard.type === 'store' &&
				userInfo.vipInfo &&
				userInfo.vipInfo.storeVipCardInfo &&
				userInfo.vipInfo.storeVipCardInfo.expirationTime > Date.now() &&
				(userInfo.vipInfo.storeVipCardInfo.level > vipCard.level ||
					userInfo.vipInfo.storeVipCardInfo.settlementWay != vipCard.settlementWay)) {
				await transaction.commit()
				return {
					code: 500,
					msg: '非法操作'
				}

			}
			if (payType != "tt") {
				let order = {
					total_fee: vipCard.price,
					payment_fee: vipCard.price,
					user_id: userInfo._id,
					user_nickname: userInfo.nickname || userInfo.username,
					user_phone: userInfo.mobile,
					platform: "mp-weixin",
					items: [{
						count: 1,
						...vipCard
					}],
					status: 1,
					use_balance: false,
					create_time: Date.now(),
					create_by: userInfo.nickname,
					type: 'openVip'
				}
				await dbHelper.insert("t3ds-order", order, transaction)
				await transaction.commit()
				return {
					code: 200,
					result: order
				}
			} else {
				let order = {
					total_fee: vipCard.price,
					payment_fee: vipCard.price,
					user_id: userInfo._id,
					user_nickname: userInfo.nickname || userInfo.username,
					platform: "mp-tt",
					items: [{
						count: 1,
						...vipCard
					}],
					status: 1,
					use_balance: false,
					create_time: Date.now(),
					create_by: userInfo.nickname,
					type: 'openVip'
				}
				await dbHelper.insert("t3ds-order", order, transaction)
				await transaction.commit()
				return {
					code: 200,
					result: order
				}
			}

		} catch (e) {
			await transaction.rollback()
			console.error(e)
			return {
				code: 500,
				msg: e.message
			}
		}
	}

	async genRechargeOrder(payType, amount) {
		let transaction = await this.db.startTransaction()
		try {
			let userInfo = await dbHelper.getById("uni-id-users", this.ctx.auth.uid, transaction)
			if (payType != "tt") {
				if (!userInfo.mobile) {
					await transaction.commit()
					return {
						code: 500,
						msg: '请先绑定手机号'
					}
				}
				let order = {
					total_fee: amount,
					payment_fee: amount,
					user_id: userInfo._id,
					user_nickname: userInfo.nickname || userInfo.username,
					user_phone: userInfo.mobile,
					platform: "mp-weixin",
					items: [],
					status: 1,
					use_balance: false,
					create_time: Date.now(),
					create_by: userInfo.nickname,
					type: 'recharge'
				}
				await dbHelper.insert("t3ds-order", order, transaction)
				await transaction.commit()
				return {
					code: 200,
					result: order
				}
			} else {
				let order = {
					total_fee: amount,
					payment_fee: amount,
					user_id: userInfo._id,
					user_nickname: userInfo.nickname || userInfo.username,
					platform: "mp-toutiao",
					items: [],
					status: 1,
					use_balance: false,
					create_time: Date.now(),
					create_by: userInfo.nickname,
					type: 'recharge'
				}
				await dbHelper.insert("t3ds-order", order, transaction)
				await transaction.commit()
				return {
					code: 200,
					result: order
				}
			}





		} catch (e) {
			await transaction.rollback()
			console.error(e)
			return {
				code: 500,
				msg: e.message
			}
		}
	}

	async genRentOrder(goodsId, count = 1) {
		let transaction
		try {
			let userInfo = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
			if (!userInfo.mobile) {
				return {
					code: 500,
					msg: '请先绑定手机号'
				}
			}
			transaction = await this.db.startTransaction()
			let goods = await dbHelper.getById("t3ds-goods-rent", goodsId, transaction)
			if (!goods) {
				await transaction.commit()
				return {
					code: 500,
					msg: '物品不存在'
				}
			}
			if (goods.stock <= count) {
				await transaction.commit()
				return {
					code: 500,
					msg: '库存不足'
				}
			}
			let dbCmd = this.db.command
			await transaction.collection("t3ds-goods-rent").doc(goods._id).update({
				stock: dbCmd.inc(-count)
			})
			let order = {
				total_fee: goods.pledge * count,
				payment_fee: goods.pledge * count,
				user_id: userInfo._id,
				user_nickname: userInfo.nickname || userInfo.username,
				user_phone: userInfo.mobile,
				platform: "mp-weixin",
				items: [{
					goods_id: goodsId,
					goods_name: goods.name,
					count,
				}],
				status: 1,
				use_balance: false,
				create_time: Date.now(),
				create_by: userInfo.nickname,
				type: 'rent'
			}
			await dbHelper.insert("t3ds-order", order, transaction)
			await transaction.commit()
			return {
				code: 200,
				result: order
			}
		} catch (e) {
			console.error(e)
			if (transaction) {
				await transaction.rollback()
			}
			return {
				code: 500,
				msg: e.message
			}
		}
	}

	async applyRefund({
		orderId,
		reason,
		photos,
		count = 1
	}) {
		let transaction = await this.db.startTransaction();
		let dbCmd = this.db.command
		try {
			// 2021.7.7之前过期的不许退款
			// let ticketCodes = await dbHelper.getList("t3ds-ticket-code", {
			// 	orderId: orderId
			// });
			// if (ticketCodes[0].deadline < 1625587200000) {
			// 	throw new Error("当前订单有效期在2021.7.7之前，不可退款")
			// }

			let goodsOrder = await dbHelper.getOne("t3ds-order", {
				_id: orderId
			});
			if (goodsOrder.channel !== 'self' && !goodsOrder.ticketCodes) {
				let payTime = goodsOrder.pay_time
				let expirationTime = 0
				let sku = await dbHelper.getById("t3ds-mall-sku", goodsOrder.items[0].sku_id)
				if (sku.time_limit.type === 'relative') { // 该订单有效期是相对时间
					expirationTime = payTime + 1000 * 60 * 60 * 24 * sku.time_limit.value
				} else if (sku.time_limit.type === 'absolute') { // 该订单有效期是绝对时间
					expirationTime = sku.time_limit.value
				}
				console.log(expirationTime);
				if (expirationTime < 1625587200000) {
					throw new Error("当前订单有效期在2021.7.7之前，不可退款")
				}
			}

			let order = await dbHelper.getById("t3ds-order", orderId, transaction);
			if (order.status !== 3 && order.status !== 9) {
				throw new Error("当前订单不可退款")
			}
			let applyCount = await dbHelper.getCount("t3ds-refund-apply", {
				orderSn: orderId,
				status: "WAITING"
			})
			if (applyCount > 0) {
				throw new Error("有未审核的退款申请，请等待审核后再操作")
			}
			let refundApply = {
				orderSn: order._id,
				createTime: Date.now(),
				reason,
				photos,
				count,
				status: "WAITING"
			}
			if (!order.channel || order.channel === 'self') {
				let unusedTickets = await dbHelper.getList("t3ds-ticket-code", {
					orderId: orderId,
					status: dbCmd.in([0, -1]), // 未使用 && 已过期
					// deadline: dbCmd.gt(Date.now())
				})
				if (unusedTickets.length === 0) {
					throw new Error("无可退款的票")
				}
				if (count > unusedTickets.length) {
					throw new Error("退款数量大于可退款票数")
				}
				let ticketIds = []
				for (var i = 0; i < count; i++) {
					let ticket = unusedTickets[i]
					await dbHelper.update("t3ds-ticket-code", {
						_id: ticket._id,
						status: -3
					}, transaction)
					ticketIds.push(ticket._id)
				}
				refundApply.ticketIds = ticketIds
			} else {
				if (count > order.items[0].count) {
					throw new Error("退款数量大于可退款票数")
				}
			}
			await dbHelper.insert("t3ds-refund-apply", refundApply, transaction)
			if (count === order.items[0].count) {
				await transaction.collection("t3ds-order").doc(order._id).update({
					status: 6
				})
			}
			await transaction.commit()
			//发送通知给管理员
			try {
				let goods = await dbHelper.getById("t3ds-mall-goods", order.items[0].goods_id)
				let merchant = await dbHelper.getById("uni-id-users", goods.uid)
				var admins = []
				if (!order.channel || order.channel === 'self') { // 自有商品
					admins = await dbHelper.getList("uni-id-users", {
						role: dbCmd.eq("admin").or(dbCmd.eq("region_mgr")),
						city: merchant.city
					})
				} else { // 渠道商品
					admins = await dbHelper.getList("uni-id-users", {
						role: dbCmd.eq("admin").or(dbCmd.eq("channel_service")).or(dbCmd.eq(
							'region_mgr')),
						city: merchant.city
					})
				}
				let unionIds = admins.filter(item => {
					return item.merchant_info && item.merchant_info.wx_unionid != undefined
				}).map(item => {
					return item.merchant_info.wx_unionid
				})
				console.log("管理员unionIds", unionIds);
				if (unionIds.length) {
					let wxPubUsers = await dbHelper.getList("t3ds-wx-pub-user", {
						unionId: dbCmd.in(unionIds),
						city: merchant.city
					})
					if (wxPubUsers.length) {
						console.log("发送通知给如下openId", wxPubUsers.map(item => {
							return item.openId;
						}));
						let member = await dbHelper.getById("uni-id-users", order.user_id)
						let isSuperVip = member.vipInfo && member.vipInfo.storeVipCardInfo &&
							member.vipInfo.storeVipCardInfo.expirationTime >= Date.now() &&
							member.vipInfo.storeVipCardInfo.settlementWay === 'time'
						// 总共需要退的钱
						let totalFee
						if (isSuperVip && order.items[0].discountsForVip) {
							totalFee = count * (order.items[0].price - order.items[0].discountsForVip);
						} else {
							totalFee = count * order.items[0].price;
						}
						// 退款扣除30%
						let refundFee = Math.round(totalFee - totalFee * 0.3)
						for (var i = 0; i < wxPubUsers.length; i++) {
							let u = wxPubUsers[i];
							let temp = await dbHelper.getOne('t3ds-region', {
								'city.value': merchant.city
							})
							let tempId = temp.templateMsgs.find(item => {
								return item.templateName === '退款审核通知'
							}).templateID
							await wxPubApi.sendTemplateMsg(merchant.city, {
								touser: u.openId,
								template_id: tempId,
								miniprogram: {
									appid: "wxa7e5444036dea6af",
									pagepath: "pagesAdmin/platform/order/order-refund-detail?applyId=" +
										refundApply._id
								},
								data: {
									first: {
										value: "您有一条新的退款申请需要审批"
									},
									keyword1: {
										value: order.items[0].goods_name.substring(0, 30)
									},
									keyword2: {
										value: order.user_nickname || '微信用户'
									},
									keyword3: {
										value: `${refundFee / 100} 元`
									},
									keyword4: {
										value: moment().tz("Asia/Shanghai").format(
											"YYYY-MM-DD HH:mm:ss")
									},
									keyword5: {
										value: reason
									},
									remark: {
										value: '请及时处理'
									}
								}
							})
						}
					} else {
						console.error("没有找到任何管理员公众号用户");
					}
				} else {
					console.error("没有找到任何管理员unionId");
				}
			} catch (e) {
				console.error("发送通知遇到错误", e);
			}
			return refundApply
		} catch (e) {
			console.error(e)
			await transaction.rollback()
			throw e
		}
	}

	/**
	 * 取消预约
	 */
	async cancelSubscribe({
		orderId,
		reason,
		photos,
		count
	}) {
		let transaction = await this.db.startTransaction();
		let dbCmd = this.db.command
		try {
			let goodsOrder = await dbHelper.getOne("t3ds-order", {
				_id: orderId
			});
			if (goodsOrder.channel !== 'self' && !goodsOrder.ticketCodes) {
				let payTime = goodsOrder.pay_time
				let expirationTime = 0
				let sku = await dbHelper.getById("t3ds-mall-sku", goodsOrder.items[0].sku_id)
				if (sku.time_limit.type === 'relative') { // 该订单有效期是相对时间
					expirationTime = payTime + 1000 * 60 * 60 * 24 * sku.time_limit.value
				} else if (sku.time_limit.type === 'absolute') { // 该订单有效期是绝对时间
					expirationTime = sku.time_limit.value
				}
				console.log(expirationTime);
				if (expirationTime < 1625587200000) {
					throw new Error("当前订单有效期在2021.7.7之前，不可退款")
				}
			}

			let order = await dbHelper.getById("t3ds-order", orderId, transaction);
			if (order.status !== 3 && order.status !== 9) {
				throw new Error("当前订单不可退款")
			}
			let applyCount = await dbHelper.getCount("t3ds-refund-apply", {
				orderSn: orderId,
				status: "WAITING"
			})
			if (applyCount > 0) {
				throw new Error("有未审核的退款申请，请等待审核后再操作")
			}
			let refundApply = {
				orderSn: order._id,
				createTime: Date.now(),
				reason,
				photos,
				count,
				status: "WAITING"
			}
			if (!order.channel || order.channel === 'self') {
				let unusedTickets = await dbHelper.getList("t3ds-ticket-code", {
					orderId: orderId,
					status: dbCmd.in([0, -1]), // 未使用 && 已过期
					// deadline: dbCmd.gt(Date.now())
				})
				if (unusedTickets.length === 0) {
					throw new Error("无可退款的票")
				}
				if (count > unusedTickets.length) {
					throw new Error("退款数量大于可退款票数")
				}
				let ticketIds = []
				for (var i = 0; i < count; i++) {
					let ticket = unusedTickets[i]
					await dbHelper.update("t3ds-ticket-code", {
						_id: ticket._id,
						status: -3
					}, transaction)
					ticketIds.push(ticket._id)
				}
				refundApply.ticketIds = ticketIds
			} else {
				if (count > order.items[0].count) {
					throw new Error("退款数量大于可退款票数")
				}
			}
			await dbHelper.insert("t3ds-refund-apply", refundApply, transaction)
			if (count === order.items[0].count) {
				await transaction.collection("t3ds-order").doc(order._id).update({
					status: 6
				})
			}
			await transaction.commit()
			//发送通知给管理员
			try {
				let goods = await dbHelper.getById("t3ds-mall-goods", order.items[0].goods_id)
				let merchant = await dbHelper.getById("uni-id-users", goods.uid)
				var admins = []
				if (!order.channel || order.channel === 'self') { // 自有商品
					admins = await dbHelper.getList("uni-id-users", {
						role: dbCmd.eq("admin").or(dbCmd.eq("region_mgr")),
						city: merchant.city
					})
				} else { // 渠道商品
					admins = await dbHelper.getList("uni-id-users", {
						role: dbCmd.eq("admin").or(dbCmd.eq("channel_service")).or(dbCmd.eq(
							'region_mgr')),
						city: merchant.city
					})
				}

				let unionIds = admins.filter(item => {
					return item.merchant_info && item.merchant_info.wx_unionid != undefined
				}).map(item => {
					return item.merchant_info.wx_unionid
				})
				console.log("管理员unionIds", unionIds);
				if (unionIds.length) {
					let wxPubUsers = await dbHelper.getList("t3ds-wx-pub-user", {
						unionId: dbCmd.in(unionIds),
						city: merchant.city
					})
					if (wxPubUsers.length) {
						console.log("发送通知给如下openId", wxPubUsers.map(item => {
							return item.openId;
						}));
						let member = await dbHelper.getById("uni-id-users", order.user_id)
						let isSuperVip = member.vipInfo && member.vipInfo.storeVipCardInfo &&
							member.vipInfo.storeVipCardInfo.expirationTime >= Date.now() &&
							member.vipInfo.storeVipCardInfo.settlementWay === 'time'
						// 总共需要退的钱
						let totalFee
						if (isSuperVip && order.items[0].discountsForVip) {
							totalFee = count * (order.items[0].price - order.items[0].discountsForVip);
						} else {
							totalFee = count * order.items[0].price;
						}
						// 退款扣除30%
						let refundFee = Math.round(totalFee - totalFee * 0.3)
						for (var i = 0; i < wxPubUsers.length; i++) {
							let u = wxPubUsers[i];
							let temp = await dbHelper.getOne('t3ds-region', {
								'city.value': merchant.city
							})
							let tempId = temp.templateMsgs.find(item => {
								return item.templateName === '退款审核通知'
							}).templateID
							await wxPubApi.sendTemplateMsg(merchant.city, {
								touser: u.openId,
								template_id: tempId,
								miniprogram: {
									appid: "wxa7e5444036dea6af",
									pagepath: "pagesAdmin/platform/order/order-refund-detail?applyId=" +
										refundApply._id
								},
								data: {
									first: {
										value: "您有一条新的退款申请需要审批"
									},
									keyword1: {
										value: order.items[0].goods_name.substring(0, 30)
									},
									keyword2: {
										value: order.user_nickname || '微信用户'
									},
									keyword3: {
										value: `${refundFee / 100} 元`
									},
									keyword4: {
										value: moment().tz("Asia/Shanghai").format(
											"YYYY-MM-DD HH:mm:ss")
									},
									keyword5: {
										value: reason
									},
									remark: {
										value: '请及时处理'
									}
								}
							})
						}
					} else {
						console.error("没有找到任何管理员公众号用户");
					}
				} else {
					console.error("没有找到任何管理员unionId");
				}
			} catch (e) {
				console.error("发送通知遇到错误", e);
			}
			return refundApply
		} catch (e) {
			console.error(e)
			await transaction.rollback()
			throw e
		}
	}

	async auditRefund({
		applyId,
		fullRefund,
		damages,
		rejected,
		rejectReason
	}) {
		let transaction = await this.db.startTransaction();
		let dbCmd = this.db.command
		try {
			console.log('xxx', applyId)
			let apply = await dbHelper.getById("t3ds-refund-apply", applyId, transaction)
			if (!apply) {
				throw new Error("退款申请不存在")
			}
			if (apply.status != 'WAITING') {
				throw new Error("已审核，不能重复操作")
			}
			let order = await dbHelper.getById("t3ds-order", apply.orderSn, transaction)

			if (rejected) {
				apply.status = "REJECTED"
				apply.rejectReason = rejectReason
				await dbHelper.update("t3ds-refund-apply", {
					_id: applyId,
					status: "REJECTED",
					rejectReason
				}, transaction)
				if (apply.ticketIds && apply.ticketIds.length) {
					for (var i = 0; i < apply.ticketIds.length; i++) {
						let id = apply.ticketIds[i]
						await dbHelper.update("t3ds-ticket-code", {
							_id: id,
							status: 0
						}, transaction)
					}
				}
				if (apply.count === order.items[0].count) {
					await dbHelper.update("t3ds-order", {
						_id: order._id,
						status: 3
					}, transaction)
				}
				await transaction.commit();
				// 发送通知给被拒退用户
				try {
					let userInfoRes = await dbHelper.getById("uni-id-users", order.user_id)
					let mallGoodsRes = await dbHelper.getById("t3ds-mall-goods", order.items[0].goods_id)
					let mallGoodsRegion = mallGoodsRes.stores[0].city
					let wxPubUsersRes = await dbHelper.getOne("t3ds-wx-pub-user", {
						unionId: userInfoRes.wx_unionid,
						city: mallGoodsRegion
					})
					let regionRes = await dbHelper.getOne('t3ds-region', {
						'city.value': mallGoodsRegion
					})
					let tempId = regionRes.templateMsgs.find(item => {
						return item.templateName === '退款审核结果通知'
					}).templateID
					console.log(
						`即将通过公众号区域：${wxPubUsersRes.city}，发送退款审核结果通知（模板id：${tempId}）给用户：${userInfoRes.id}`)
					await wxPubApi.sendTemplateMsg(mallGoodsRegion, {
						touser: wxPubUsersRes.openId,
						template_id: tempId,
						miniprogram: {
							appid: "wx609a0a547e98415d",
							pagepath: "pagesFoo/order/order"
						},
						data: {
							first: {
								value: "您有一条新的退款审核结果通知"
							},
							keyword1: {
								value: order._id
							},
							keyword2: {
								value: order.items[0].goods_name
							},
							keyword4: {
								value: '拒绝退款'
							},
							remark: {
								value: `拒绝原因：${rejectReason}\n审核时间：${moment().tz("Asia/Shanghai").format("YYYY-MM-DD HH:mm:ss")}`
							}
						}
					})
				} catch (e) {
					console.error("发送退款审核结果通知遇到错误：", e);
				}
				return apply
			}
			if (order.total_fee) {
				let member = await dbHelper.getById("uni-id-users", order.user_id)
				let isSuperVip = member.vipInfo && member.vipInfo.storeVipCardInfo &&
					member.vipInfo.storeVipCardInfo.expirationTime >= Date.now() &&
					member.vipInfo.storeVipCardInfo.settlementWay === 'time'
				// 总共需要退的钱
				let totalFee
				if (isSuperVip && order.items[0].discountsForVip) {
					totalFee = apply.count * (order.items[0].price - order.items[0].discountsForVip);
				} else {
					totalFee = apply.count * order.items[0].price;
				}
				// 退款扣除30%
				let refundFee
				if (fullRefund) {
					refundFee = totalFee
				} else {
					refundFee = Math.round(totalFee - totalFee * 0.3);
				}

				let account = await dbHelper.getOne("t3ds-account", {
					userId: order.user_id
				})
				// 需要发起微信退款的钱, 需要退回余额的钱
				let refundFee2, refundBalance;
				if (order.use_balance) {
					// 使用了多少余额里面的钱
					let balance = order.total_fee - order.payment_fee;

					if (refundFee > balance) {
						refundBalance = balance;
						refundFee2 = refundFee - balance;
					} else {
						refundBalance = refundFee;
					}
					console.log("退至余额的金额", (refundBalance / 100).toFixed(2));
					account.balance += refundBalance;
					account.total += refundBalance;
					await transaction.collection("t3ds-account").doc(account._id).update({
						balance: dbCmd.inc(refundBalance),
						total: dbCmd.inc(refundBalance)
					})
					let accountLog = {
						accountId: account._id,
						userId: order.user_id,
						createTime: Date.now(),
						income: refundBalance,
						orderId: order._id,
						total: account.total,
						tradeType: 6
					}
					await dbHelper.insert("t3ds-account-log", accountLog, transaction);
				} else {
					refundFee2 = refundFee;
				}
				let user = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
				let refundApply = {
					_id: applyId,
					auditBy: user.username,
					auditTime: Date.now(),
					status: "REFUNDED",
					fullRefund
				};
				if (damages) {
					refundApply.damages = parseInt(damages)
				}
				if (refundBalance) {
					refundApply.refundBalance = refundBalance;
				}
				var orderStatus = 8
				if (refundFee2) {
					console.log("退至第三方账户的金额", (refundFee2 / 100).toFixed(2));
					refundApply.refundFee = refundFee2;
					refundApply.status = "REFUNDING";
					orderStatus = 7
				} else {
					refundApply.refundTime = Date.now();
					if (apply.ticketIds && apply.ticketIds.length) {
						for (var i = 0; i < apply.ticketIds.length; i++) {
							let id = apply.ticketIds[i]
							await transaction.collection("t3ds-ticket-code").doc(id).update({
								status: -4
							})
						}
					}
				}
				let refundTicketCount = await dbHelper.getCount("t3ds-ticket-code", {
					orderId: order._id,
					status: dbCmd.in([-3, -4])
				})
				if (refundTicketCount === order.items[0].count) {
					await dbHelper.update("t3ds-order", {
						_id: order._id,
						status: orderStatus
					})
				}

				await dbHelper.update("t3ds-refund-apply", refundApply, transaction);
				Object.assign(apply, refundApply)

				//还原销量和库存
				await transaction.collection("t3ds-mall-sku").doc(order.items[0].sku_id).update({
					stock: dbCmd.inc(apply.count),
					sellCount: dbCmd.inc(-apply.count)
				})

				await transaction.collection("t3ds-mall-goods").doc(order.items[0].goods_id).update({
					totalStock: dbCmd.inc(apply.count),
					totalSellCount: dbCmd.inc(-apply.count)
				})

				let sku = await dbUtil.getById({
					collection: "t3ds-mall-sku",
					id: order.items[0].sku_id,
					field: {
						settle_flag: true,
						is_on_seckill: true
					}
				})
				if (sku.is_on_seckill && sku.seckill_status == 1) {
					// 如果是秒杀商品，需要添加临时库存
					await transaction.collection("t3ds-mall-sku").doc(order.items[0].sku_id).update({
						amountNow: dbCmd.inc(apply.count)
					})
				}
				if (sku.settle_flag) {
					// 如果是置换商品，需要扣除佣金
					let accountLogs = await dbHelper.getList("t3ds-account-log", {
						settled: false,
						tradeType: dbCmd.in([1, 3, 4, 7, 8]),
						orderId: order._id
					});
					if (accountLogs.length) {
						for (var i = 0; i < accountLogs.length; i++) {
							var log = accountLogs[i];
							log = await dbHelper.getById("t3ds-account-log", log._id, transaction)
							if (log.settled) {
								continue
							}
							let brokrage = Math.round(log.income / order.items[0].count * apply.count)
							// await transaction.collection("t3ds-account-log").doc(log._id).update({
							// 	income: dbCmd.inc(-brokrage)
							// })
							console.log("扣除佣金", brokrage / 100);
							let account = await dbUtil.getById({
								collection: "t3ds-account",
								id: log.accountId,
								transaction
							})
							account.settle -= brokrage
							account.total -= brokrage
							await transaction.collection("t3ds-account").doc(log.accountId).update({
								settle: dbCmd.inc(-brokrage),
								total: dbCmd.inc(-brokrage)
							})
							let accountLog = {
								accountId: account._id,
								userId: order.user_id,
								createBy: user.username,
								createTime: Date.now(),
								income: -brokrage,
								orderId: order._id,
								settled: true,
								total: account.total,
								settle: account.settle,
								frozen: account.frozen,
								tradeType: -5
							}
							await dbHelper.insert("t3ds-account-log", accountLog, transaction);
							if (refundTicketCount === order.items[0].count) {
								console.log("更新分销者账户日志为已结算");
								await transaction.collection("t3ds-account-log").doc(log._id).update({
									settled: true,
									settleTime: Date.now()
								});
							}
						}
					}
				}

				//如果是达人并且有返现，则扣除返现
				let accountLog = await dbHelper.getOne("t3ds-account-log", {
					orderId: order._id,
					tradeType: 2
				})
				if (accountLog) {
					//扣除金額
					let fee = accountLog.income / order.items[0].count * apply.count
					if (order.channel === 'self' || !order.channel) {
						await transaction.collection("t3ds-account").doc(account._id).update({
							total: dbCmd.inc(-fee),
							settle: dbCmd.inc(-fee),
							updateTime: Date.now(),
							updateBy: user.username || ""
						})
						account.total -= fee;
						account.settle -= fee;
					} else {
						await transaction.collection("t3ds-account").doc(account._id).update({
							total: dbCmd.inc(-fee),
							balance: dbCmd.inc(-fee),
							updateTime: Date.now(),
							updateBy: user.username || ""
						})
						account.total -= fee;
						account.balance -= fee;
					}
					await transaction.collection("t3ds-account-log").doc(accountLog._id).update({
						invalid: true, //无效的
					})
					let accountLog2 = {
						accountId: account._id,
						userId: order.user_id,
						createBy: user.username,
						createTime: Date.now(),
						income: -fee,
						orderId: order._id,
						settled: true,
						total: account.total,
						settle: account.settle,
						frozen: account.frozen,
						tradeType: -5
					}
					await dbHelper.insert("t3ds-account-log", accountLog2, transaction);
				}

				// 从商家账户扣除损失
				if (damages) {
					let goods = await dbHelper.getById("t3ds-mall-goods", order.items[0].goods_id)
					let merchantAccount = await dbHelper.getOne("t3ds-account", {
						userId: goods.uid
					})
					let damages_ = parseInt(damages)
					await transaction.collection('t3ds-account')
						.doc(merchantAccount._id)
						.update({
							balance: dbCmd.inc(-damages_),
							total: dbCmd.inc(-damages_)
						})
					await transaction.collection('t3ds-account-log')
						.add({
							accountId: merchantAccount._id,
							userId: goods.uid,
							createBy: user.username,
							createTime: Date.now(),
							income: -damages_,
							orderId: order._id,
							settled: true,
							total: merchantAccount.total -= damages_,
							refundApplyId: refundApply._id,
							tradeType: -3
						})
				}


				if (refundFee2) {
					if (order.pay_type == "ttpay") {
						console.log("发起头条退款", order);
						const res = await this.ttPayRefundService(order._id, new Date().getTime().toString(),
							"订单退款", Math.round(refundFee2))
					} else {
						console.log("发起微信退款", order);
						let uniPayInstance = payUtil.getPayInstance(order.pay_type, order.platform);
						let res = await uniPayInstance.refund({
							outTradeNo: order._id,
							outRefundNo: refundApply._id,
							totalFee: Math.round(order.payment_fee), // 订单总金额，支付宝可不填此项
							refundFee: Math.round(refundFee2), // 退款总金额
						})
					}
				}


			} else {
				let user = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
				let refundApply = {
					_id: applyId,
					auditBy: user.username,
					auditTime: Date.now(),
					refundFee: 0,
					status: "REFUNDED",
					refundTime: Date.now()
				}
				if (apply.ticketIds && apply.ticketIds.length) {
					for (var i = 0; i < apply.ticketIds.length; i++) {
						let id = apply.ticketIds[i]
						await transaction.collection("t3ds-ticket-code").doc(id).update({
							status: -4
						})
					}
				}
				let refundTicketCount = await dbHelper.getCount("t3ds-ticket-code", {
					orderId: order._id,
					status: dbCmd.in([-3, -4])
				})
				if (refundTicketCount === order.items[0].count) {
					await dbHelper.update("t3ds-order", {
						_id: order._id,
						status: 8
					})
				}

				await dbHelper.update("t3ds-refund-apply", refundApply, transaction);
				Object.assign(apply, refundApply)
			}
			await transaction.commit();
			return apply
		} catch (e) {
			console.error("审核退款申请遇到错误，事务回滚", e);
			await transaction.rollback();
			throw e
		}
	}

	async refund({
		orderId,
		reason,
		fullRefund, //是否全额退款
		damages, //因为商家原因而退款使平台造成的损失由商家承担，此为金额
		count = 1 //需要退多少张票，渠道订单必填
	}) {
		let transaction = await this.db.startTransaction();
		let dbCmd = this.db.command
		try {
			let order = await dbHelper.getById("t3ds-order", orderId, transaction);
			if (!order) {
				await transaction.commit()
				return {
					code: 500,
					msg: "订单不存在"
				}
			}
			if (order.status !== 3) {
				await transaction.commit()
				return {
					code: 500,
					msg: "订单已使用或未付款"
				}
			}
			let unusedTicketCount = 0
			let unusedTickets
			if (!order.channel || order.channel === 'self') {
				unusedTickets = await dbHelper.getList("t3ds-ticket-code", {
					orderId: orderId,
					status: 0,
					deadline: dbCmd.gt(Date.now())
				})
				if (unusedTickets.length === 0) {
					return {
						code: 500,
						msg: "票券已过期，无法退款"
					}
				}
				unusedTicketCount = unusedTickets.length
			} else {
				if (!count || count > order.items[0].count) {
					return {
						code: 500,
						msg: "退票数量不正确"
					}
				}
				unusedTicketCount = count
			}

			if (order.total_fee) {
				let sku = await dbHelper.getById("t3ds-mall-sku", order.items[0].sku_id)
				let member = await dbHelper.getById("uni-id-users", order.user_id)
				let isSuperVip = member.vipInfo && member.vipInfo.storeVipCardInfo &&
					member.vipInfo.storeVipCardInfo.expirationTime >= Date.now() &&
					member.vipInfo.storeVipCardInfo.settlementWay === 'time'
				// 总共需要退的钱
				let totalFee
				if (isSuperVip && order.items[0].discountsForVip) {
					totalFee = unusedTicketCount * (order.items[0].price - order.items[0].discountsForVip);
				} else {
					totalFee = unusedTicketCount * order.items[0].price;
				}
				// 退款扣除30%
				let refundFee
				if (fullRefund) {
					refundFee = totalFee
				} else {
					refundFee = Math.round(totalFee - totalFee * 0.3);
				}
				console.log(
					`是否全额退款：${fullRefund ? '是' : '否'}\n扣商家的钱：${damages || '0'}分\n总退款金额：${refundFee} 分\n未使用的票数量：${unusedTicketCount}`
				);

				let account = await dbHelper.getOne("t3ds-account", {
					userId: order.user_id
				})
				// 需要发起微信退款的钱, 需要退回余额的钱
				let refundFee2, refundBalance;
				if (order.use_balance) {
					// 使用了多少余额里面的钱
					let balance = order.total_fee - order.payment_fee;

					if (refundFee > balance) {
						refundBalance = balance;
						refundFee2 = refundFee - balance;
					} else {
						refundBalance = refundFee;
					}
					console.log("退至余额的金额", (refundBalance / 100).toFixed(2));
					account.balance += refundBalance;
					account.total += refundBalance;
					await transaction.collection("t3ds-account").doc(account._id).update({
						balance: dbCmd.inc(refundBalance),
						total: dbCmd.inc(refundBalance)
					})
					let accountLog = {
						accountId: account._id,
						userId: order.user_id,
						createTime: Date.now(),
						income: refundBalance,
						orderId: orderId,
						total: account.total,
						tradeType: 6
					}
					await dbHelper.insert("t3ds-account-log", accountLog, transaction);
				} else {
					refundFee2 = refundFee;
				}
				let user = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
				let refundApply = {
					count,
					orderSn: orderId,
					createTime: Date.now(),
					reason: reason,
					auditBy: user.username,
					auditTime: Date.now(),
					status: "REFUNDED",
					fullRefund
				};
				if (damages) {
					refundApply.damages = parseInt(damages)
				}
				if (refundBalance) {
					refundApply.refundBalance = refundBalance;
				}
				var orderStatus = 8; // 已退款
				if (refundFee2) {
					console.log("退至第三方账户的金额", (refundFee2 / 100).toFixed(2));
					refundApply.refundFee = refundFee2;
					refundApply.status = "REFUNDING";
					orderStatus = 7; //退款中
				} else {
					refundApply.refundTime = Date.now();
				}

				await dbHelper.insert("t3ds-refund-apply", refundApply, transaction);
				await transaction.collection("t3ds-order").doc(orderId).update({
					status: orderStatus,
					update_time: Date.now()
				})
				if (unusedTickets) {
					for (var i = 0; i < unusedTicketCount; i++) {
						let tick = unusedTickets[i]
						await transaction.collection("t3ds-ticket-code").doc(tick._id).update({
							status: -2
						})
					}
				}

				//还原销量和库存
				await transaction.collection("t3ds-mall-sku").doc(order.items[0].sku_id).update({
					stock: dbCmd.inc(unusedTicketCount),
					sellCount: dbCmd.inc(-unusedTicketCount)
				})

				await transaction.collection("t3ds-mall-goods").doc(order.items[0].goods_id).update({
					totalStock: dbCmd.inc(unusedTicketCount),
					totalSellCount: dbCmd.inc(-unusedTicketCount)
				})
				if (sku.settle_flag) {
					// 如果是置换商品，需要扣除佣金
					let accountLogs = await dbHelper.getList("t3ds-account-log", {
						settled: false,
						tradeType: dbCmd.in([1, 3, 4, 7, 8]),
						orderId: order._id
					});
					if (accountLogs.length) {
						for (var i = 0; i < accountLogs.length; i++) {
							var log = accountLogs[i];
							log = await dbHelper.getById("t3ds-account-log", log._id, transaction)
							if (log.settled) {
								continue
							}
							let brokrage = Math.round(log.income / order.items[0].count * unusedTicketCount)
							// await transaction.collection("t3ds-account-log").doc(log._id).update({
							// 	income: dbCmd.inc(-brokrage)
							// })
							console.log("扣除佣金", brokrage / 100);
							let account = await dbUtil.getById({
								collection: "t3ds-account",
								id: log.accountId,
								transaction
							})
							account.settle -= brokrage
							account.total -= brokrage
							await transaction.collection("t3ds-account").doc(log.accountId).update({
								settle: dbCmd.inc(-brokrage),
								total: dbCmd.inc(-brokrage)
							})
							let accountLog = {
								accountId: account._id,
								userId: order.user_id,
								createBy: user.username,
								createTime: Date.now(),
								income: -brokrage,
								orderId: order._id,
								settled: true,
								total: account.total,
								settle: account.settle,
								frozen: account.frozen,
								tradeType: -5
							}
							await dbHelper.insert("t3ds-account-log", accountLog, transaction);
							await transaction.collection("t3ds-account-log").doc(log._id).update({
								settled: true,
								settleTime: Date.now()
							});
						}
					}
				}

				//如果是达人并且有返现，则扣除返现
				let accountLog = await dbHelper.getOne("t3ds-account-log", {
					orderId: order._id,
					tradeType: 2
				})
				if (accountLog) {
					//扣除金額
					let fee = Math.round(accountLog.income / order.items[0].count * unusedTicketCount)
					if (order.channel === 'self' || !order.channel) {
						await transaction.collection("t3ds-account").doc(account._id).update({
							total: dbCmd.inc(-fee),
							settle: dbCmd.inc(-fee),
							updateTime: Date.now(),
							updateBy: user.username || ""
						})
						account.total -= fee;
						account.settle -= fee;
					} else {
						await transaction.collection("t3ds-account").doc(account._id).update({
							total: dbCmd.inc(-fee),
							balance: dbCmd.inc(-fee),
							updateTime: Date.now(),
							updateBy: user.username || ""
						})
						account.total -= fee;
						account.balance -= fee;
					}
					await transaction.collection("t3ds-account-log").doc(accountLog._id).update({
						invalid: true, //无效的
					})
					let accountLog2 = {
						accountId: account._id,
						userId: order.user_id,
						createBy: user.username,
						createTime: Date.now(),
						income: -fee,
						orderId: orderId,
						settled: true,
						total: account.total,
						tradeType: -5
					}
					await dbHelper.insert("t3ds-account-log", accountLog2, transaction);
				}

				// 从商家账户扣除损失
				if (damages) {
					let goods = await dbHelper.getById("t3ds-mall-goods", order.items[0].goods_id)
					let merchantAccount = await dbHelper.getOne("t3ds-account", {
						userId: goods.uid
					})
					let damages_ = parseInt(damages)
					await transaction.collection('t3ds-account')
						.doc(merchantAccount._id)
						.update({
							balance: dbCmd.inc(-damages_),
							total: dbCmd.inc(-damages_)
						})
					await transaction.collection('t3ds-account-log')
						.add({
							accountId: merchantAccount._id,
							userId: goods.uid,
							createBy: user.username,
							createTime: Date.now(),
							income: -damages_,
							orderId: orderId,
							settled: true,
							total: merchantAccount.total -= damages_,
							refundApplyId: refundApply._id,
							tradeType: -3
						})
				}



				if (refundFee2) {
					if (order.pay_type == "ttpay") {
						console.log("发起头条退款", order);
						const res = await this.ttPayRefundService(order._id, new Date().getTime().toString(),
							"订单退款", Math.round(refundFee2))
					} else {
						console.log("发起微信退款", order);
						let uniPayInstance = payUtil.getPayInstance(order.pay_type, order.platform);
						let res = await uniPayInstance.refund({
							outTradeNo: order._id,
							outRefundNo: refundApply._id,
							totalFee: Math.round(order.payment_fee), // 订单总金额，支付宝可不填此项
							refundFee: Math.round(refundFee2), // 退款总金额
						})
					}
				}



				order.status = orderStatus;
				order.update_time = Date.now();
			} else {
				let user = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
				let refundApply = {
					count,
					orderSn: orderId,
					createTime: Date.now(),
					reason: reason,
					auditBy: user.username,
					auditTime: Date.now(),
					status: "REFUNDED",
					fullRefund,
					refundTime: Date.now()
				};
				if (damages) {
					refundApply.damages = parseInt(damages)
				}

				await dbHelper.insert("t3ds-refund-apply", refundApply, transaction);
				await transaction.collection("t3ds-order").doc(orderId).update({
					status: 8,
					update_time: Date.now()
				})
				if (unusedTickets) {
					for (var i = 0; i < unusedTicketCount; i++) {
						let tick = unusedTickets[i]
						await transaction.collection("t3ds-ticket-code").doc(tick._id).update({
							status: -2
						})
					}
				}

				// 从商家账户扣除损失
				if (damages) {
					let goods = await dbHelper.getById("t3ds-mall-goods", order.items[0].goods_id)
					let merchantAccount = await dbHelper.getOne("t3ds-account", {
						userId: goods.uid
					})
					let damages_ = parseInt(damages)
					await transaction.collection('t3ds-account')
						.doc(merchantAccount._id)
						.update({
							balance: dbCmd.inc(-damages_),
							total: dbCmd.inc(-damages_)
						})
					await transaction.collection('t3ds-account-log')
						.add({
							accountId: merchantAccount._id,
							userId: goods.uid,
							createBy: user.username,
							createTime: Date.now(),
							income: -damages_,
							orderId: orderId,
							settled: true,
							total: merchantAccount.total -= damages_,
							refundApplyId: refundApply._id,
							tradeType: -3
						})
				}

				order.status = orderStatus;
				order.update_time = Date.now();
			}
			await transaction.commit();
			return {
				code: 200,
				result: order
			}
		} catch (e) {
			console.log("立即退款遇到错误，事务回滚", e);
			await transaction.rollback();
			return {
				code: 500,
				msg: e.message
			}
		}
	}

	//获取头条支付状态
	async getTtQuerystate(out_order_no) {
		const params = {
			"app_id": "ttc46fb2d25b563c6601",
			"out_order_no": out_order_no,
		}
		params.sign = this.ttPayMd5(params)
		let resp = await uniCloud.httpclient.request(
			"https://developer.toutiao.com/api/apps/ecpay/v1/query_order", {
				method: 'POST',
				data: params,
				contentType: 'json', // 指定以application/json发送data内的数据
				dataType: 'json' // 指定返回值为json格式，自动进行parse
			})
		return resp
	}

	async getOrderDetail(orderId, userLocation, type) {
		try {
			const db = this.db
			const dbCmd = db.command
			const $ = dbCmd.aggregate

			let order = await dbHelper.getById("t3ds-order", orderId)
			if (!order) {
				return {
					code: 500,
					msg: '订单不存在'
				}
			}
			if (order.status >= 1 && order.status < 3) {
				console.log('实付: ', order.payment_fee)
				if (order.payment_fee) {
					let provider = order.pay_type
					let platform = order.platform


					// let uniPayInstance = payUtil.getPayInstance(provider, platform);
					// let queryResult = await uniPayInstance.orderQuery({
					// 	outTradeNo: order._id
					// })
					// if (queryResult.tradeState === 'SUCCESS' || queryResult.tradeState === 'FINISHED') {
					// 	await orderHelper.handleOrderPaid(orderId, Date.now())
					// 	order = await dbHelper.getById("t3ds-order", orderId)
					// }

					const res = await this.getTtQuerystate(order._id)
					console.log(res)
					// if (res.data.payment_info.order_status == 'SUCCESS' || res.data.payment_info.order_status =='FINISHED') {
					if (true) {
						await orderHelper.handleOrderPaid(orderId, Date.now())
						order = await dbHelper.getById("t3ds-order", orderId)
					}
				} else {
					await orderHelper.handleOrderPaid(orderId, Date.now())
					order = await dbHelper.getById("t3ds-order", orderId)
				}
			}

			if (order.couponId) {
				let couponMemberRes = await dbHelper.getById("t3ds-coupon-member", order.couponId)
				order.couponInfo = {
					_id: couponMemberRes._id,
					type: couponMemberRes.type,
					value: couponMemberRes.value
				}
			}
			if (order.user_phone) {
				let phone = order.user_phone;
				order.user_phone = phone.substring(0, 3) + "****" + phone.substring(7);
			}

			let userRes = await dbHelper.getById("uni-id-users", order.user_id)
			order.id = userRes.id
			if (order.type === 'goods') {
				let goodsId = order.items[0].goods_id;
				let goods = await dbHelper.getById("t3ds-mall-goods", goodsId)
				if (goods.type === 'ticket') {
					let skuId = order.items[0].sku_id;
					let sku = await dbHelper.getById("t3ds-mall-sku", skuId)
					order.can_refund = sku.can_refund || false
					order.isTicketPackage = sku.receipts && sku.receipts.length && true
					order.ticketCodes = await dbHelper.getList("t3ds-ticket-code", {
						orderId: order._id
					});
					console.log(order._id)
					console.log(order.ticketCodes)


					// 获取渠道商品订单的过期时间
					if (goods.channel !== 'self' && !order.ticketCodes.length) {
						let payTime = order.pay_time
						let expirationTime = 0
						if (sku.time_limit.type === 'relative') { // 该订单有效期是相对时间
							expirationTime = payTime + 1000 * 60 * 60 * 24 * sku.time_limit.value
						} else if (sku.time_limit.type === 'absolute') { // 该订单有效期是绝对时间
							expirationTime = sku.time_limit.value
						}
						order.ticketCodes[0] = {
							deadline: expirationTime
						}
					}
					if (sku.receipts && sku.receipts.length) {
						order.ticketCodes.forEach(item => {
							item.hasReceipts = true
						})
					}
					if (userLocation) {
						let $ = dbCmd.aggregate;
						let storeRes = await this.db.collection("t3ds-store").aggregate()
							.geoNear({
								distanceField: 'distance',
								spherical: true,
								near: new this.db.Geo.Point(Number(userLocation.longitude), Number(
									userLocation.latitude)),
								query: {
									'_id': $.in(goods.store_ids || [])
								}
							})
							.project({
								photos: false,
								introduction: false
							})
							.end();
						if (storeRes.data.length) {
							order.store = storeRes.data;
						}
					} else {
						let storeRes = await this.db.collection("t3ds-store").where({
							_id: dbCmd.in(goods.store_ids || [])
						}).field({
							photos: false,
							introduction: false
						}).get();
						if (storeRes.data.length) {
							order.store = storeRes.data;
						}
					}
					if (!order.channel || order.channel === 'self') {
						order.useableCount = await dbHelper.getCount("t3ds-ticket-code", {
							orderId: order._id,
							status: 0,
							deadline: dbCmd.gte(Date.now())
						})
						order.overdueCount = await dbHelper.getCount("t3ds-ticket-code", dbCmd.and([{
							orderId: order._id
						}, dbCmd.or([{
							status: 1
						}, {
							deadline: dbCmd.lt(Date.now())
						}])]))
						order.usedCount = await dbHelper.getCount("t3ds-ticket-code", {
							orderId: order._id,
							status: 1
						})
						order.refundedCount = await dbHelper.getCount("t3ds-ticket-code", {
							orderId: order._id,
							status: dbCmd.eq(-3).or(dbCmd.eq(-4))
						})
					} else {
						let refundCountRes = await this.db.collection("t3ds-refund-apply").aggregate()
							.match({
								orderSn: orderId,
								status: dbCmd.neq('FAILED').and(dbCmd.neq('REJECTED'))
							})
							.group({
								_id: "$orderSn",
								count: $.sum("$count")
							})
							.end()
						if (refundCountRes.data.length) {
							order.refundedCount = refundCountRes.data[0].count
						} else {
							order.refundedCount = 0
						}
						if (order.usedCount == undefined) {
							order.usedCount = 0
						}
						if (order.overdueCount == undefined) {
							order.overdueCount = 0
						}
						order.useableCount = order.items[0].count - order.usedCount - order.overdueCount - order
							.refundedCount
					}
					let refundApplyRes = await this.db.collection("t3ds-refund-apply").where({
							orderSn: orderId
						})
						.orderBy("createTime", "desc")
						.limit(1)
						.get()
					if (refundApplyRes.data.length) {
						order.refundApply = refundApplyRes.data[0]
					}
				}
			} else if (order.type === 'subscribe') { // 预约订单
				let item = order.items[0]

				let room = {}
				let store = {}
				if (item.room_id) {
					room = await dbHelper.getById("t3ds-store-room", item.room_id)
					store = await dbHelper.getById("t3ds-store", room.storeId)
				} else {
					store = await dbHelper.getById("t3ds-store", item.store_id)
				}

				order.roomInfo = {
					roomId: room._id || '',
					roomName: room.name || '',
					price: order.items[0].room_price || store.unifyPrice,
					storeId: store._id,
					storeName: store.name,
					address: store.address,
					location: store.location,
					cooperationMode: store.cooperationMode
				}

				let script = await dbHelper.getById("t3ds-script", item.script_id)
				order.scriptInfo = {
					_id: script._id,
					name: script.name,
					cover: script.cover,
					storyTags: script.storyTags,
					classTags: script.classTags,
					price: order.items[0].script_price,
					playTime: script.playTime,
					difficulty: script.difficulty,
					simpleTag: script.simpleTag,
					standardPlayers: script.standardPlayers,
					limitPlayers: script.limitPlayers,
					minPlayers: script.minPlayers,
					maleCount: script.maleCount,
					femaleCount: script.femaleCount
				}
				let motorcade = await dbHelper.getById("t3ds-subscribe-motorcade", order.motorcadeId)
				if (!motorcade) {
					order.motorcadeInfo = {
						startTime: item.start_time,
						endTime: item.end_time,
						currentMaleCount: item.maleCount,
						currentFemaleCount: item.femaleCount,
						minPlayers: script.minPlayers
					}
					return {
						code: 200,
						result: order
					}
				}
				order.motorcadeInfo = motorcade

				let memberRes = await db.collection("t3ds-order").aggregate()
					.match({
						_id: dbCmd.in(motorcade.orderIds)
					})
					.lookup({
						from: 'uni-id-users',
						localField: 'user_id',
						foreignField: '_id',
						as: 'member'
					})
					.unwind('$member')
					.replaceRoot({
						newRoot: '$member'
					})
					.project({
						_id: 1,
						nickname: 1,
						username: 1,
						id: 1,
						avatar: 1,
						creditScore: 1,
						comment: 1
					})
					.end()
				let obj = {}
				memberRes.data = memberRes.data.reduce(function(item, next) {
					obj[next._id] ? '' : obj[next._id] = true && item.push(next)
					return item
				}, [])
				memberRes.data.forEach(item => {
					if (item.id == motorcade.initiator) {
						item.initiator = true
					}
				})
				order.members = memberRes.data
			} else if (order.type === 'tearoom') { // 茶室订单
				let item = order.items[0]

				let room = await dbHelper.getById("t3ds-store-room", item.room_id)
				let store = await dbHelper.getById("t3ds-store", room.storeId)

				order.roomInfo = {
					roomId: room._id,
					roomName: room.name,
					price: order.items[0].room_price || store.unifyPrice,
					storeId: store._id,
					storeName: store.name,
					address: store.address,
					location: store.location,
					cooperationMode: store.cooperationMode
				}
			} else if (order.type === 'renewal') { // 续时订单
				let item = order.items[0]

				let room = {}
				let store = {}
				if (item.script_id) { // 剧本杀续时订单
					if (item.room_id) {
						room = await dbHelper.getById("t3ds-store-room", item.room_id)
						store = await dbHelper.getById("t3ds-store", room.storeId)
					} else {
						store = await dbHelper.getById("t3ds-store", item.store_id)
					}
					let script = await dbHelper.getById("t3ds-script", item.script_id)
					let motorcade = await dbHelper.getById("t3ds-subscribe-motorcade", order.motorcadeId)

					order.scriptInfo = {
						_id: script._id,
						name: script.name,
						cover: script.cover,
						storyTags: script.storyTags,
						classTags: script.classTags,
						price: order.items[0].script_price,
						playTime: script.playTime,
						difficulty: script.difficulty,
						simpleTag: script.simpleTag,
						standardPlayers: script.standardPlayers,
						limitPlayers: script.limitPlayers,
						minPlayers: script.minPlayers,
						maleCount: script.maleCount,
						femaleCount: script.femaleCount
					}
					order.roomInfo = {
						roomId: room._id || '',
						roomName: room.name || '',
						storeId: store._id,
						storeName: store.name,
						address: store.address,
						location: store.location,
						price: order.items[0].room_price || store.unifyPrice,
						cooperationMode: store.cooperationMode
					}

					// 续时订单数组-按倒序排，用于在界面上显示所有续时记录
					motorcade.renewalOrders_inverted = JSON.parse(JSON.stringify(motorcade.renewalOrders))
						.reverse()

					order.motorcadeInfo = motorcade
					let memberRes = await db.collection("t3ds-order").aggregate()
						.match({
							_id: dbCmd.in(motorcade.orderIds)
						})
						.lookup({
							from: 'uni-id-users',
							localField: 'user_id',
							foreignField: '_id',
							as: 'member'
						})
						.unwind('$member')
						.replaceRoot({
							newRoot: '$member'
						})
						.project({
							_id: 1,
							nickname: 1,
							username: 1,
							id: 1,
							avatar: 1,
							creditScore: 1
						})
						.end()
					let obj = {}
					memberRes.data = memberRes.data.reduce(function(item, next) {
						obj[next._id] ? '' : obj[next._id] = true && item.push(next)
						return item
					}, [])
					memberRes.data.forEach(item => {
						if (item.id == motorcade.initiator) {
							item.initiator = true
						}
					})
					order.members = memberRes.data
				} else { // 茶室续时订单
					room = await dbHelper.getById("t3ds-store-room", item.room_id)
					store = await dbHelper.getById("t3ds-store", room.storeId)
					order.roomInfo = {
						roomId: room._id,
						roomName: room.name,
						// storeId: store._id,
						// storeName: store.name,
						// address: store.address,
						// location: store.location,
						price: order.items[0].room_price || store.unifyPrice,
						cooperationMode: store.cooperationMode
					}

					// 续时订单数组-按倒序排，用于在界面上显示所有续时记录
					let tearoomOrderRes = await dbHelper.getById("t3ds-order", order.tearoomOrderId)
					order.renewalOrders_inverted = JSON.parse(JSON.stringify(tearoomOrderRes.renewalOrders))
						.reverse()
				}
			}

			return {
				code: 200,
				result: order
			}
		} catch (e) {
			return {
				code: 500,
				msg: e.message
			}
		}
	}

	calcRefundFee({
		order,
		count = 1
	}) {
		if (!order.total_fee) {
			return {
				refundFee: 0,
				backRefundFee: 0,
				refundBalance: 0,
				serviceChargePercent: '0',
				serviceCharge: 0
			}
		}
		// 总金额
		let totalFee = Math.round(count * (order.items[0].price - order.discounts_for_vip / count))
		// 需要扣除的金额
		let serviceCharge = Math.round(totalFee * 0.3)
		// 退款金额
		let refundFee = Math.round(totalFee - serviceCharge)
		// 退回非余额的钱, 需要退回余额的钱
		let backRefundFee, refundBalance
		if (order.use_balance) {
			// 使用了多少余额里面的钱
			let balance = order.total_fee - order.payment_fee

			if (refundFee > balance) {
				refundBalance = balance;
				backRefundFee = refundFee - balance
			} else {
				refundBalance = refundFee
				backRefundFee = 0
			}
		} else {
			backRefundFee = refundFee
		}
		return {
			refundFee,
			backRefundFee,
			refundBalance,
			serviceChargePercent: '30%',
			serviceCharge
		}
	}

	async getOrderRefundDetail({
		orderId,
		userLocation
	}) {
		try {
			const dbCmd = this.db.command
			const $ = dbCmd.aggregate
			var order = await dbHelper.getById("t3ds-order", orderId)
			if (!order) {
				return {
					code: 500,
					msg: '订单不存在'
				}
			}
			if (order.user_phone) {
				let phone = order.user_phone;
				order.user_phone = phone.substring(0, 3) + "****" + phone.substring(7);
			}

			if (order.type === 'goods') {
				let goodsId = order.items[0].goods_id;
				let goods = await dbHelper.getById("t3ds-mall-goods", goodsId)
				if (goods.type === 'ticket') {
					let skuId = order.items[0].sku_id;
					let sku = await dbHelper.getById("t3ds-mall-sku", skuId)
					order.isTicketPackage = sku.receipts && sku.receipts.length && true
					order.ticketCodes = await dbHelper.getList("t3ds-ticket-code", {
						orderId: order._id
					});
					if (sku.receipts && sku.receipts.length) {
						order.ticketCodes.forEach(item => {
							item.hasReceipts = true
						})
					}
					if (userLocation) {
						let $ = dbCmd.aggregate;
						let storeRes = await this.db.collection("t3ds-store").aggregate()
							.geoNear({
								distanceField: 'distance',
								spherical: true,
								near: new this.db.Geo.Point(Number(userLocation.longitude), Number(
									userLocation.latitude)),
								query: {
									'_id': $.in(goods.store_ids || [])
								}
							})
							.project({
								photos: false,
								introduction: false
							})
							.end();
						if (storeRes.data.length) {
							order.store = storeRes.data[0];
						}
					} else {
						let storeRes = await this.db.collection("t3ds-store").where({
							_id: dbCmd.in(goods.store_ids || [])
						}).field({
							photos: false,
							introduction: false
						}).get();
						if (storeRes.data.length) {
							order.store = storeRes.data[0];
						}
					}
					let refundFee = this.calcRefundFee({
						order
					})
					Object.assign(order, refundFee)
					if (!order.channel || order.channel === 'self') {
						let maxRefundCount = await dbHelper.getCount("t3ds-ticket-code", {
							orderId: orderId,
							status: 0,
							deadline: dbCmd.gt(Date.now())
						})
						order.maxRefundCount = maxRefundCount
					} else {
						let refundCountRes = await this.db.collection("t3ds-refund-apply").aggregate()
							.match({
								orderSn: orderId,
								status: dbCmd.neq('FAILED').and(dbCmd.neq('REJECTED'))
							})
							.group({
								_id: "$orderSn",
								count: $.sum("$count")
							})
							.end()
						if (refundCountRes.data.length) {
							order.maxRefundCount = order.items[0].count - refundCountRes.data[0].count
						} else {
							order.maxRefundCount = order.items[0].count
						}
					}
				}
			}
			return order
		} catch (e) {
			throw e
		}
	}

	async cancelOrder(orderId) {
		let transaction
		try {
			let order = await dbHelper.getById("t3ds-order", orderId)
			if (!order) {
				return {
					code: 500,
					msg: '订单不存在'
				}
			}
			if (order.status !== 1) {
				return {
					code: 500,
					msg: '订单状态不对，无法取消'
				}
			}
			let user = await dbHelper.getById("uni-id-users", this.ctx.auth.uid)
			if (user._id !== order.user_id) {
				return {
					code: 500,
					msg: '无权限'
				}
			}
			transaction = await this.db.startTransaction();
			const dbCmd = this.db.command

			// 非剧本杀续时订单在这退款
			if (!(order.type === 'renewal' && order.motorcadeId)) {
				if (order.use_balance) {
					//退回至余额账户
					let account = await dbHelper.getOne("t3ds-account", {
						userId: user._id
					})
					let fee = order.total_fee - order.payment_fee - (order.discount_fee || 0);
					await transaction.collection("t3ds-account").doc(account._id).update({
						frozen: dbCmd.inc(-fee),
						balance: dbCmd.inc(fee)
					})
				}
				if (order.couponId) {
					await transaction.collection('t3ds-coupon-member').doc(order.couponId).update({
						used: false,
						usedTime: '',
						updateTime: Date.now(),
						updateBy: '系统'
					});
				}
				await transaction.collection("t3ds-order").doc(order._id).update({
					status: -1
				})
			}

			console.log("order: ", order);
			// 取消订单
			switch (order.type) {
				case 'subscribe': // 预约剧本杀
				case 'tearoom': // 预约茶室
					console.log('取消预约剧本杀或预约茶室');
					// if (order.motorcadeId) {
					// let motorcadeRes = await dbHelper.getById("t3ds-subscribe-motorcade", order.motorcadeId)
					// let logs = motorcadeRes.operationLogs || []
					// 车队就一个人
					// if ((motorcadeRes.currentFemaleCount + motorcadeRes.currentMaleCount) === 1) {
					//   logs.push({
					//     {
					//       "action": "取消订单",
					//       "createBy": this.ctx.auth.uid,
					//       "time": Date.now()
					//     }
					//   })
					//   await transaction.collection("t3ds-subscribe-motorcade").doc(order.motorcadeId).update({
					//     status: -1,
					//     operationLogs: logs
					//   })
					// }
					// 有多个车队成员
					// if ((motorcadeRes.currentFemaleCount + motorcadeRes.currentMaleCount) > 1) {
					//   logs.push({
					//     {
					//       "action": "退出车队",
					//       "createBy": this.ctx.auth.uid,
					//       "time": Date.now()
					//     }
					//   })
					//   await transaction.collection("t3ds-subscribe-motorcade").doc(order.motorcadeId).update({
					//     operationLogs: logs
					//   })
					// }
					// }
					break;
				case 'renewal': // 剧本杀续时、茶室续时不做处理
					// if (order.motorcadeId) { // 剧本杀续时
					//   let motorcadeRes = await dbHelper.getById("t3ds-subscribe-motorcade", order.motorcadeId, transaction)
					//   let renewalOrdersIdRes = motorcadeRes.renewalOrders[0].renewalOrdersId.map(item => item.renewalOrderId)
					//   for (let renewalOrderId of renewalOrdersIdRes) {
					//     let renewalOrderRes = await dbHelper.getById("t3ds-order", renewalOrderId, transaction)
					//     if (renewalOrderRes.use_balance) {
					//     	//退回至余额账户
					//     	let account = await dbHelper.getOne("t3ds-account", { userId: renewalOrderRes.user_id }, transaction)
					//     	let fee = renewalOrderRes.total_fee - renewalOrderRes.payment_fee;
					//     	await transaction.collection("t3ds-account").doc(account._id).update({
					//     		frozen: dbCmd.inc(-fee),
					//     		balance: dbCmd.inc(fee)
					//     	})
					//     }
					//     await transaction.collection('t3ds-order').doc(renewalOrderId).remove()
					//   }
					//   await transaction.collection('t3ds-subscribe-motorcade').doc(order.motorcadeId).update({ renewalOrders: dbCmd.shift() })
					// } else { // 茶室续时
					//   await transaction.collection('t3ds-order').doc(order.tearoomOrderId).update({ renewalOrders: dbCmd.shift() })
					// }
					break;
				default: // 商品订单，会员开通订单，充值订单，租借物品订单
					// 还原库存
					let item = order.items[0];
					await transaction.collection("t3ds-mall-sku").doc(item.sku_id).update({
						stock: dbCmd.inc(item.count)
					})
					await transaction.collection("t3ds-mall-goods").doc(item.goods_id).update({
						totalStock: dbCmd.inc(item.count)
					})
					//还原销量
					await transaction.collection("t3ds-mall-sku").doc(item.sku_id).update({
						sellCount: dbCmd.inc(-item.count)
					})
					await transaction.collection("t3ds-mall-goods").doc(item.goods_id).update({
						totalSellCount: dbCmd.inc(-item.count)
					})
					break;
			}

			await transaction.commit();
			return {
				code: 200
			}
		} catch (e) {
			console.log("取消订单遇到错误", e);
			if (transaction) {
				await transaction.rollback();
			}
			return {
				code: 500,
				msg: e.message
			}
		}
	}

	async exitMotorcade(motorcadeId, orderId) {
		const transaction = await this.db.startTransaction();
		try {
			const db = this.db
			const dbCmd = db.command
			const $ = dbCmd.aggregate

			let motorcadeRes = await dbHelper.getById("t3ds-subscribe-motorcade", motorcadeId)
			if (!motorcadeRes) {
				await transaction.commit()
				return {
					code: 500,
					msg: '车队不存在'
				}
			}
			if (motorcadeRes.status !== 0) {
				await transaction.commit()
				return {
					code: 500,
					msg: '车队不处于拼车中，无法退出车队'
				}
			}
			let orderRes = await dbHelper.getById("t3ds-order", orderId)
			if (!orderRes) {
				await transaction.commit()
				return {
					code: 500,
					msg: '订单不存在'
				}
			}
			if (!(orderRes.status === 2 || orderRes.status === 3)) {
				await transaction.commit()
				return {
					code: 500,
					msg: '当前订单不可退款'
				}
			}

			/* 获取扣款费率 */
			let rateRes = await dbHelper.getList("t3ds-system-config", {
				key: dbCmd.in(['scriptRate', 'venueRate'])
			})
			let deductionsRate = 0
			for (let item of rateRes) {
				deductionsRate += item.value / 100
			}

			/* 退出车队 */
			let orderIndex = motorcadeRes.orderIds.indexOf(orderId)
			if (orderIndex === -1) {
				await transaction.commit()
				return {
					code: 500,
					msg: '订单不存在于该车队中'
				}
			}
			// console.log("要退出车队人数: ", orderRes.items[0].count);
			if (motorcadeRes.currentMaleCount + motorcadeRes.currentFemaleCount - orderRes.items[0].count ===
				0) { // 取消车队：更新车队 --> 更新订单 --> 退款 --> 更新包间
				console.log('取消车队');
				let data = {
					motorcade: motorcadeRes,
					serviceCharge: deductionsRate,
					handleMan: '用户',
					reason: '车队中最后一人退出车队',
					transaction
				}
				await orderHelper.cancelMotorcade(data)
			} else { // 仅退出车队
				console.log('仅退出车队');
				let logs = motorcadeRes.operationLogs || []
				logs.unshift({
					action: '车队成员退出车队',
					time: Date.now(),
					createBy: '用户'
				})

				let orderListRes = await dbHelper.getList("t3ds-order", {
					_id: dbCmd.in(motorcadeRes.orderIds)
				})
				let orderListRes2 = orderListRes.map(item => item.user_id)
				let usersRes = await dbHelper.getList("uni-id-users", {
					_id: dbCmd.in(orderListRes2)
				})
				console.log("usersRes: ", usersRes.map(item => item.id));
				let count = 0
				let successionInitiator = motorcadeRes.initiator
				for (let i = 0; i < usersRes.length; i++) {
					if (motorcadeRes.initiator === usersRes[i].id) {
						count++
					} else {
						successionInitiator = usersRes[i].id
					}
				}

				let currentOrderUserRes = await dbHelper.getOne("uni-id-users", {
					_id: orderRes.user_id
				})
				successionInitiator = (motorcadeRes.initiator === currentOrderUserRes.id && count === 1) ?
					successionInitiator : motorcadeRes.initiator
				console.log("successionInitiator: ", successionInitiator);

				motorcadeRes.orderIds.splice(orderIndex, 1)
				console.log("transaction: ", transaction);
				await transaction.collection("t3ds-subscribe-motorcade").doc(motorcadeId).update({
					orderIds: motorcadeRes.orderIds,
					currentMaleCount: dbCmd.inc(-orderRes.items[0].maleCount),
					currentFemaleCount: dbCmd.inc(-orderRes.items[0].femaleCount),
					initiator: successionInitiator,
					operationLogs: logs
				})

				await orderHelper.refundNow({
					order: orderRes,
					reason: '车队成员退出车队',
					serviceChargeRate: deductionsRate,
					transaction
				})
			}

			/* 返回 */
			await transaction.commit()
			return {
				code: 200,
				msg: '成功退出车队！'
			}
		} catch (e) {
			await transaction.rollback()
			return {
				code: 500,
				msg: e.message
			}
		}
	}

	// 茶室订单 + 茶室续时订单
	async genTearoomOrder({
		orderType,
		startTime,
		endTime,
		storeId,
		roomId,
		useBalance = false,
		couponId, //优惠券id
		// buyCardId, //会员卡/折扣卡id
		shareManId,
		tearoomOrderId // 当前茶室订单id
	}) {
		const transaction = await this.db.startTransaction();

		const dbCmd = this.db.command
		const $ = dbCmd.aggregate

		try {
			let coupon = await verifyCoupon(transaction, this.ctx.auth.uid, couponId, startTime, orderType,
				storeId)

			let storeRes = await dbHelper.getById("t3ds-store", storeId, transaction)

			let roomRes = null
			if (roomId) {
				roomRes = await dbHelper.getById("t3ds-store-room", roomId, transaction)
				if (!roomRes) {
					throw new Error("房间不存在")
				}
				if (!roomRes.enabled) {
					throw new Error("房间不可用")
				}
				let roomLocked = await this.checkRoomLocked(roomRes._id, startTime, endTime)
				if (roomLocked) {
					await transaction.commit();
					return {
						code: 500,
						msg: '该时间段的房间已被预定，请选择其他时间段'
					}
				}
			}

			let orderRes = {}
			if (orderType === 'renewal') {
				orderRes = await dbHelper.getById("t3ds-order", tearoomOrderId, transaction)
				if (orderRes.status < 3 || orderRes.status > 5) {
					throw new Error("已结束或已取消，不能续时了")
				}
			}

			let pricePerHour = 0
			let time = (endTime - startTime) / oneHourInMills
			let count = 1

			// 更新账户余额
			let {
				discountsForVip,
				totalFee,
				paymentFee,
				discount_fee,
				member,
				use_balance_fee,
				income,
				account
			} = await updataAccountBalance(transaction, this.ctx, time, pricePerHour, roomRes, storeRes, count,
				coupon, useBalance)

			// 生成茶室订单
			let item = {
				start_time: startTime,
				end_time: endTime,
				room_id: roomRes._id,
				room_name: roomRes.name,
				room_capacity: roomRes.capacity,
				room_price: roomRes.price,
				settlement_price: roomRes.settlementPrice,
				discountsForVip: discountsForVip,
				store_id: storeRes._id,
				store_name: storeRes.name
			}
			let order = {
				total_fee: Math.round(totalFee),
				discounts_for_vip: discountsForVip || 0,
				payment_fee: Math.round(paymentFee),
				user_id: member._id,
				user_nickname: member.nickname || '微信用户',
				user_phone: member.mobile,
				platform: "mp-weixin",
				status: 1,
				items: [item],
				use_balance: useBalance ? true : false,
				use_balance_fee: use_balance_fee || 0,
				create_time: Date.now(),
				create_by: member.nickname || '微信用户'
			}
			if (orderType === 'renewal') {
				order.type = 'renewal'
				order.tearoomOrderId = tearoomOrderId
			} else {
				order.type = 'tearoom'
			}
			if (coupon) {
				order.couponId = couponId
				order.discount_fee = discount_fee
			}
			if (shareManId) {
				order.shareManId = parseInt(shareManId);
			}
			await dbHelper.insert("t3ds-order", order, transaction);
			if (income) {
				await dbHelper.insert("t3ds-account-log", {
					accountId: account._id,
					total: account.total,
					income: income,
					tradeType: -1,
					orderId: order._id,
					settled: true,
					createTime: Date.now(),
					createBy: member.id + ''
				}, transaction);
			}

			if (orderType === 'renewal') {
				// renewalOrders = [
				//   {
				//     没有都支付,
				//     续时多久,
				//     续时结束时间,
				//     续时订单id
				//   }
				// ]
				if (orderRes.renewalOrders && orderRes.renewalOrders.length > 0) {
					orderRes.renewalOrders.unshift({
						notPaidInFull: true,
						renewalDuration: order.items[0].end_time - order.items[0].start_time,
						renewalEndTime: order.items[0].end_time,
						renewalOrderId: order._id
					})
				} else {
					orderRes.renewalOrders = [{
						notPaidInFull: true,
						renewalDuration: order.items[0].end_time - order.items[0].start_time,
						renewalEndTime: order.items[0].end_time,
						renewalOrderId: order._id
					}]
				}
				await dbHelper.update("t3ds-order", {
					_id: orderRes._id,
					renewalOrders: orderRes.renewalOrders
				}, transaction);
			}

			await transaction.commit();

			try {
				if (!order.payment_fee) {
					await orderHelper.handleOrderPaid(order._id, Date.now())
					order = await dbHelper.getById("t3ds-order", order._id)
				}
			} catch (e) {}

			console.log("创建订单成功, 提交事务");
			return {
				code: 200,
				result: order
			}
		} catch (e) {
			console.error("创建订单遇到错误, 事务回滚", e);
			await transaction.rollback();
			return {
				code: 500,
				result: e
			}
		}
	}

	/**
	 * 更新未支付的订单信息、续时订单信息
	 */
	async uptateUnpaidOrder({
		orderType,
		couponId, //优惠券id
		startTime,
		endTime,
		scriptId,
		maleCount,
		femaleCount,
		roomId,
		useBalance = false,
		// buyCardId, //会员卡/折扣卡id
		shareManId,
		orderId
	}) {
		const transaction = await this.db.startTransaction();

		const dbCmd = this.db.command
		const $ = dbCmd.aggregate

		try {
			let count = scriptId ? (maleCount + femaleCount) : 1
			console.log("count: ", count, maleCount, femaleCount);
			let orderRes = await dbHelper.getById("t3ds-order", orderId)
			console.log("store_id: ", orderRes.items[0].store_id);
			let coupon = await verifyCoupon(transaction, this.ctx.auth.uid, couponId, startTime, orderType,
				orderRes.items[0].store_id, orderRes.motorcadeId || '')

			let script = null
			if (scriptId) {
				script = await dbHelper.getById("t3ds-script", scriptId)
			}
			let room = {}
			let store = {}
			if (roomId) {
				room = await dbHelper.getById("t3ds-store-room", roomId)
			} else {
				store = await dbHelper.getById("t3ds-store", orderRes.items[0].store_id)
			}

			let pricePerHour = script ? script.price / script.playTime : 0
			let time = (endTime - startTime) / oneHourInMills

			// 更新账户余额
			let {
				discountsForVip,
				totalFee,
				paymentFee,
				discount_fee,
				member,
				use_balance_fee,
				income,
				account
			} = await updataAccountBalance(transaction, this.ctx, time, pricePerHour, room, store, count,
				coupon, useBalance)

			// 更新该未支付的续时订单
			orderRes.items[0].discountsForVip = discountsForVip
			orderRes.discounts_for_vip = discountsForVip || 0
			orderRes.payment_fee = Math.round(paymentFee)
			orderRes.use_balance = useBalance ? true : false
			orderRes.use_balance_fee = use_balance_fee || 0
			if (coupon) {
				orderRes.couponId = couponId
				orderRes.discount_fee = discount_fee
			}
			if (shareManId) {
				orderRes.shareManId = parseInt(shareManId);
			}
			await dbHelper.update("t3ds-order", orderRes, transaction);

			if (income) {
				await dbHelper.insert("t3ds-account-log", {
					accountId: account._id,
					total: account.total,
					income: income,
					tradeType: -1,
					orderId: orderRes._id,
					settled: true,
					createTime: Date.now(),
					createBy: member.id + ''
				}, transaction);
			}

			await transaction.commit();

			switch (orderType) {
				case 'subscribe': // 剧本杀订单
				case 'tearoom': // 茶室订单
					if (!orderRes.payment_fee) {
						await orderHelper.handleOrderPaid(orderRes._id, Date.now())
						orderRes = await dbHelper.getById("t3ds-order", orderRes._id)
					}
					break;
				case 'renewal': // 续时订单
					if (orderRes.tearoomOrderId) { // 茶室续时订单
						if (!orderRes.payment_fee) {
							await orderHelper.handleOrderPaid(orderRes._id, Date.now())
							orderRes = await dbHelper.getById("t3ds-order", orderRes._id)
						}
					} else { // 剧本杀续时订单
						if (!orderRes.motorcadeId) break
						// 续时订单是否未全部支付
						let motorcadeRes = await dbHelper.getById("t3ds-subscribe-motorcade", orderRes
							.motorcadeId)
						if (!motorcadeRes.renewalOrders.length) break
						let renewalOrdersId = JSON.parse(JSON.stringify(motorcadeRes.renewalOrders[0]
							.renewalOrdersId))
						let index = renewalOrdersId.findIndex(item => item.renewalOrderId === orderId)
						renewalOrdersId.splice(index, 1) // 过滤掉当前续时订单
						let notPaidInFull = false // 已全部支付
						for (let item of renewalOrdersId) {
							let count = await dbHelper.getCount('t3ds-order', {
								_id: item.renewalOrderId,
								status: dbCmd.or(dbCmd.eq(1), dbCmd.eq(-1))
							})
							if (count > 0) { // 存在未支付的
								notPaidInFull = true
								break
							}
						}
						motorcadeRes.renewalOrders[0].notPaidInFull = notPaidInFull
						if (!notPaidInFull) {
							motorcadeRes.endTime = motorcadeRes.renewalOrders[0].renewalEndTime
						}
						await dbHelper.update("t3ds-subscribe-motorcade", {
							_id: motorcadeRes._id,
							endTime: motorcadeRes.endTime,
							['renewalOrders.' + 0]: {
								notPaidInFull
							}
						});
					}
					break;
				default:
					break;
			}

			return orderRes
		} catch (e) {
			console.error("更新订单遇到错误, 事务回滚", e);
			await transaction.rollback();
			throw e
		}
	}

	//获取当前用户当前未锁定规格票券的数量
	async getTicketCount({
		skuId
	}) {
		let dbCmd = this.db.command
		try {
			let goodOrder = await this.db.collection("t3ds-order").where({
					user_id: this.ctx.auth.uid,
					'items.sku_id': skuId,
					type: "goods",
					status: dbCmd.in([2, 3])
				})
				.field({
					_id: true
				})
				.get()
			let orderIds = []
			goodOrder.data.forEach(item => {
				orderIds.push(item._id)
			})
			let count = await this.db.collection("t3ds-ticket-code").where({
					status: 0,
					orderId: dbCmd.in(orderIds)
				})
				.field({
					_id: true
				})
				.count()
			return count.total
		} catch (e) {
			throw e
		}
	}

	//获取当前规格的车队列表
	async getSkuMotorcadeList({
		skuId,
		themeId
	}) {
		let dbCmd = this.db.command
		try {
			let motorcadeList = await this.db.collection("t3ds-motorcade").where({
					sku_id: skuId,
					theme_id: themeId,
					startTime: dbCmd.gt(Date.now())
				})
				.get()
			for (let z = 0; z < motorcadeList.data.length; z++) {
				let item = motorcadeList.data[z]
				let userList = []
				let userIdList = await this.db.collection("t3ds-order").where({
						_id: dbCmd.in(item.orderIds)
					})
					.field({
						_id: true,
						user_id: true
					})
					.get()
				userIdList.data.forEach(item => {
					userList.push(item.user_id)
				})
				if (userList.length > 0) {
					//车队成员信息（第一个为发起人）
					for (let i = 0; i < userList.length; i++) {
						let temp = await this.db.collection("uni-id-users").where({
								_id: userList[i]
							})
							.field({
								_id: true,
								nickname: true,
								avatar: true
							})
							.get()
						userList[i] = temp.data[0]
					}
				}
				motorcadeList.data[z].userList = userList
			}
			return motorcadeList.data
		} catch (e) {
			throw e
		}
	}

	//通过订单ID获取车队订单的详细信息
	async getMotorcadeDetail({
		orderId
	}) {
		let dbCmd = this.db.command
		try {
			let result = {
				userList: []
			}
			//订单信息
			let orderDetail = await dbHelper.getById("t3ds-order", orderId)
			if (!orderDetail) {
				throw new Error("订单不存在")
			}
			result.orderDetail = orderDetail
			//车队信息
			let motorcadeDetail = await dbHelper.getById("t3ds-motorcade", orderDetail.motorcadeId)
			if (!motorcadeDetail) {
				throw new Error("车队不存在")
			}
			result.motorcadeDetail = motorcadeDetail
			let userIdList = await this.db.collection("t3ds-order").where({
					_id: dbCmd.in(motorcadeDetail.orderIds)
				})
				.field({
					_id: true,
					user_id: true
				})
				.get()
			userIdList.data.forEach(item => {
				result.userList.push(item.user_id)
			})
			if (result.userList.length > 0) {
				//车队成员信息（第一个为发起人）
				for (let i = 0; i < result.userList.length; i++) {
					let temp = await this.db.collection("uni-id-users").where({
							_id: result.userList[i]
						})
						.field({
							_id: true,
							nickname: true,
							avatar: true,
							creditScore: true,
							declarationDating: true
						})
						.get()
					result.userList[i] = temp.data[0]
				}
			}
			return result
		} catch (e) {
			throw e
		}
	}

	//用户点击已到店（结束车队，结算押金）
	async getToStore({
		orderId,
		userLocation
	}) {
		const transaction = await this.db.startTransaction();
		let dbCmd = this.db.command
		let $ = dbCmd.aggregate
		try {
			//订单信息
			let orderDetail = await dbHelper.getById("t3ds-order", orderId)
			if (!orderDetail) {
				throw new Error("订单不存在")
			}
			//车队信息
			let motorcadeDetail = await dbHelper.getById("t3ds-motorcade", orderDetail.motorcadeId)
			if (!motorcadeDetail) {
				throw new Error("车队不存在")
			}
			if (motorcadeDetail.status !== 2) {
				throw new Error("车队状态错误")
			}
			if (Date.now() < motorcadeDetail.endTime) {
				throw new Error("结束后才能进行此操作")
			}
			let tempTime = moment(motorcadeDetail.endTime).cnZone().add(1, 'hours').toDate().getTime()
			if (Date.now() > tempTime) {
				throw new Error("请在结束后一小时内操作")
			}
			let storeRes = await this.db.collection("t3ds-store").aggregate()
				.geoNear({
					distanceField: 'distance',
					spherical: true,
					near: new this.db.Geo.Point(Number(userLocation.longitude), Number(
						userLocation.latitude)),
					query: {
						'_id': $.eq(motorcadeDetail.storeId)
					}
				})
				.project({
					distance: true
				})
				.end();
			let tempDistance = storeRes.data[0].distance
			//console.log("qqqq",tempDistance)
			if (parseInt(tempDistance) < 20) {
				//已到店
				await orderHelper.refundDetain({
					orderId: orderDetail._id,
					judge: true,
					transaction
				})
			} else {
				throw new Error("门店不在范围中")
			}
			await transaction.commit();
			return "操作成功"
		} catch (e) {
			await transaction.rollback();
			throw e
		}
	}

	//通过车队ID获取车队的详细信息及门店信息
	async getMotorcadeAndStore({
		motorcadeId
	}) {
		let dbCmd = this.db.command
		try {
			//车队信息
			let motorcadeDetail = await dbHelper.getById("t3ds-motorcade", motorcadeId)
			if (!motorcadeDetail) {
				throw new Error("车队不存在")
			}
			let themeDetail = await this.db.collection("t3ds-theme-config").where({
					_id: motorcadeDetail.theme_id
				})
				.field({
					_id: true,
					image: true
				})
				.get()
			motorcadeDetail.themeDetail = themeDetail.data[0].image
			let storeDetail = await this.db.collection("t3ds-store").where({
					_id: motorcadeDetail.storeId
				})
				.field({
					_id: true,
					photos: true
				})
				.get()
			motorcadeDetail.storeDetail = storeDetail.data[0].photos
			let skuDetail = await this.db.collection("t3ds-mall-sku").where({
					_id: motorcadeDetail.sku_id
				})
				.field({
					_id: true,
					goods_id: true,
					share_reward: true,
					share_reward2: true,
					share_reward3: true,
					share_reward_old: true
				})
				.get()
			motorcadeDetail.skuDetail = skuDetail.data[0]
			let goodsDetail = await this.db.collection("t3ds-mall-goods").where({
					_id: skuDetail.data[0].goods_id
				})
				.field({
					_id: true,
					detail: true
				})
				.get()
			motorcadeDetail.goodsDetail = goodsDetail.data[0].detail
			let userList = []
			let userIdList = await this.db.collection("t3ds-order").where({
					_id: dbCmd.in(motorcadeDetail.orderIds)
				})
				.field({
					_id: true,
					user_id: true
				})
				.get()
			userIdList.data.forEach(item => {
				userList.push(item.user_id)
			})
			if (userList.length > 0) {
				//车队成员信息（第一个为发起人）
				for (let i = 0; i < userList.length; i++) {
					let temp = await this.db.collection("uni-id-users").where({
							_id: userList[i]
						})
						.field({
							_id: true,
							nickname: true,
							avatar: true
						})
						.get()
					userList[i] = temp.data[0]
				}
			}
			motorcadeDetail.userList = userList
			return motorcadeDetail
		} catch (e) {
			throw e
		}
	}

	//获取商品车队列表（pageNum = 0首页的车队信息）
	async getGoodsMotorcadeList({
		pageNum,
		pageSize,
		categoryId,
		userLocation,
		filter
	}) {
		let dbCmd = this.db.command
		const transaction = await this.db.startTransaction();
		const $ = dbCmd.aggregate
		try {
			let result = {}
			if (pageNum > 0) {
				let sort = {}
				if (filter) {
					if (filter.distance) {
						sort.distance = 1
					} else if (filter.startTime) {
						sort.startTime = 1
					} else if (filter.costPerPerson) {
						sort.costPerPerson = 1
					} else if (filter.currentCount) {
						sort.currentCount = 1
					}
				} else {
					sort.createTime = 1
				}
				//分页查询
				if (categoryId) {
					//有分类Id的查询
					let temp1 = await transaction.collection('t3ds-motorcade').aggregate()
						.geoNear({
							distanceField: 'distance',
							spherical: true,
							near: new this.db.Geo.Point(Number(userLocation.longitude), Number(
								userLocation.latitude)),
							query: {
								//status: dbCmd.eq(0)
								status: dbCmd.in([0, 1])
							}
						})
						.match(dbCmd.expr($.and([
							$.in(['$status', [0, 1]]),
							$.lt(['$currentCount', '$maxPlayers'])
						])))
						// .match({
						//   status: dbCmd.eq(0)
						// })
						.project({
							orderIds: 1,
							startTime: 1,
							endTime: 1,
							initiator: 1,
							costPerPerson: 1,
							address: 1,
							location: 1,
							thumbnail: 1,
							name: 1,
							sku_id: 1,
							theme_id: 1,
							storeId: 1,
							storeName: 1,
							city: 1,
							maxPlayers: 1,
							currentMaleCount: 1,
							currentFemaleCount: 1,
							currentCount: $.add(["$currentMaleCount", "$currentFemaleCount"]),
							minPlayers: 1,
							allowGetOn: 1,
							status: 1,
							createBy: 1,
							createTime: 1,
							city_district_id: 1,
							distance: 1,
						})
						.sort(sort)
						.lookup({
							from: 't3ds-mall-sku',
							let: {
								skuId: '$sku_id',
							},
							pipeline: $.pipeline()
								.match(dbCmd.expr($.and([
									$.eq(['$_id', '$$skuId'])
								])))
								.project({
									goods_id: 1,
									name: 1
								})
								.done(),
							as: 'skuDetail',
						})
						.unwind("$skuDetail")
						.lookup({
							from: 't3ds-mall-goods',
							let: {
								goodId: '$skuDetail.goods_id'
							},
							pipeline: $.pipeline()
								.match(dbCmd.expr($.and([
									$.eq(['$_id', '$$goodId'])
								])))
								.project({
									name: 1,
									category_id: 1
								})
								.done(),
							as: 'goodDetail',
						})
						.unwind("$goodDetail")
						.match({
							'goodDetail.category_id': categoryId
						})
						.skip((pageNum - 1) * pageSize)
						.limit(pageSize)
						.end()
					//console.log("qqqq",temp1)
					result = temp1.data
				} else {
					//查询所有拼车车队
					let temp2 = await transaction.collection('t3ds-motorcade').aggregate()
						.geoNear({
							distanceField: 'distance',
							spherical: true,
							near: new this.db.Geo.Point(Number(userLocation.longitude), Number(
								userLocation.latitude)),
							query: {
								//status: dbCmd.eq(0)
								status: dbCmd.in([0, 1])
							}
						})
						.match(dbCmd.expr($.and([
							$.in(['$status', [0, 1]]),
							$.lt(['$currentCount', '$maxPlayers']),
							$.gt(['$endTime', Date.now()])
						])))
						// .match({
						//   status: dbCmd.eq(0)
						// })
						.project({
							orderIds: 1,
							startTime: 1,
							endTime: 1,
							initiator: 1,
							costPerPerson: 1,
							address: 1,
							location: 1,
							thumbnail: 1,
							name: 1,
							sku_id: 1,
							theme_id: 1,
							storeId: 1,
							storeName: 1,
							city: 1,
							maxPlayers: 1,
							currentMaleCount: 1,
							currentFemaleCount: 1,
							currentCount: $.add(["$currentMaleCount", "$currentFemaleCount"]),
							minPlayers: 1,
							allowGetOn: 1,
							status: 1,
							createBy: 1,
							createTime: 1,
							city_district_id: 1,
							distance: 1,
						})
						.sort(sort)
						.lookup({
							from: 't3ds-mall-sku',
							let: {
								skuId: '$sku_id',
							},
							pipeline: $.pipeline()
								.match(dbCmd.expr($.and([
									$.eq(['$_id', '$$skuId'])
								])))
								.project({
									goods_id: 1,
									name: 1
								})
								.done(),
							as: 'skuDetail',
						})
						.unwind("$skuDetail")
						.lookup({
							from: 't3ds-mall-goods',
							let: {
								goodId: '$skuDetail.goods_id'
							},
							pipeline: $.pipeline()
								.match(dbCmd.expr($.and([
									$.eq(['$_id', '$$goodId'])
								])))
								.project({
									name: 1,
									category_id: 1
								})
								.done(),
							as: 'goodDetail',
						})
						.unwind("$goodDetail")
						.skip((pageNum - 1) * pageSize)
						.limit(pageSize)
						.end()
					console.log("wwww", temp2)
					console.log("wwww", Date.now())
					result = temp2.data
				}
				//res = motorcadeList.data
			} else {
				let motorcadeDetail = await this.db.collection("t3ds-motorcade").where({
						status: 0
					})
					.orderBy("createTime", "desc")
					.limit(1)
					.get()
				result = motorcadeDetail.data[0]
			}
			return result
		} catch (e) {
			throw e
		}
	}
}